C 動態呼叫C 編寫的DLL函式

2021-07-25 02:24:29 字數 4183 閱讀 1532

** c#動態呼叫c++編寫的dll函式

c#動態呼叫c++編寫的dll函式

動態載入 dll 需要使用 windows api 函式: loadlibrary 、 getprocaddress 以及 freelibrary 。我們可以使用 dllimport 在 c# 中使用這三個函式。

[dllimport("kernel32")]

public

static

extern

intgetprocaddress(int handle, string funcname);

[dllimport("kernel32")]

public

static

extern

intloadlibrary(string funcname);

[dllimport("kernel32")]

public

static

extern

intfreelibrary(int handle);

當我們在 c++ 中動態呼叫 dll 中的函式時,我們一般的方法是:

假設 dll 中有乙個匯出函式,函式原型如下:

bool __stdcall foo(object &object, lpvoid lpreserved);

1 、首先定義相應的函式指標:

typedef bool (__stdcall *pfoo)(object &object, lpvoid lpreserved);

2 、呼叫 loadlibrary 載入 dll :

hinstance hinst = ::loadlibraryw(dllfilename);

4 、呼叫 foo 函式:

bool bret = foo(object,(lpvoid)null);

5 、使用完後應釋放 dll :

freelibrary(hinst);

那麼在 c# 中應該怎麼做呢?方法基本上一樣,我們使用委託來代替 c++ 的函式指標,通過 .net framework 2.0 新增的函式getdelegateforfunctionpointer 來得到乙個委託的例項:

下面封裝了乙個類,通過該類我們就可以在 c# 中動態呼叫 dll 中的函式了:

public

////// 將表示函式位址的 intptr 例項轉換成對應的委託 , by jingzhongrong

/// public

static delegate getdelegatefromintptr(intptr address, type t)

////// 將表示函式位址的 int 轉換成對應的委託,by jingzhongrong

/// public

static delegate getdelegatefromintptr(int address, type t)

}

通過這個類,我們這樣呼叫 dll :

1 、宣告相應的委託(正確宣告很重要,否則不能呼叫成功,後面有詳細介紹)。

2 、載入 dll :

if (hmodule == 0)

retur nfalse;

3 、獲取相應的委託例項:

if (foo == null)

4 、呼叫函式:

foo(...);
5 、 .net 並不能自動釋放動態載入的 dll ,因此我們在使用完 dll 後應該自己釋放 dll :

下面我們將就委託應如何宣告進行相應的討論,在實際操作過程中,我發現使用 dllimport 方法和動態呼叫方法兩者在 c# 中對 dll 中函式原型的宣告是有些區別的,下面我介紹動態呼叫中委託的宣告:

1 、首先應該注意的是, c++ 中的型別和 c# 中型別的對應關係,比如 c++ 中的 long 應該對應 c# 中的 int32 而不是 long ,否則將導致呼叫結果出錯。

2 、結構的宣告使用 structlayout對結構的相應布局進行設定,具體的請檢視 msdn:

使用 layoutkind 指定結構中成員的布局順序,一般可以使用 sequential :

[structlayout(layoutkind.sequential)]

structstructversioninfo

另外,如果單獨使用內部型別沒有另外使用到字串、結構、類,可以將結構在 c# 中宣告為 class :

[structlayout(layoutkind.sequential)]

classstructversioninfo

對應 c++ 中的宣告:

typedef

struct _version_info

version_info, *pversion_info;

如果結構中使用到了字串,最好應指定相應的字符集:

[structlayout(layoutkind.sequential,charset=charset.unicode)]
部分常用的宣告對應關係(在結構中):

c++ :字串陣列

wchar_t comments[120];

c# :

[marshalas(unmanagedtype.byvaltstr, sizeconst = 120)]

public string comments;

c++ :結構成員

version_info ver;

c#public structversioninfo ver;

c++ :函式指標宣告

pfoo pfoo; // 具體宣告見文章前面部分

c#:public

int ptr pfoo; // 也可以為 public int pfoo;

如果在結構中使用到了 union ,那麼可以使用 fieldoffset 指定具體位置。

3 、委託的宣告:

當 c++ 編寫的 dll 函式需要通過指標傳出將乙個結構:如以下宣告:

void getversioninfo( version_info *ver);

對於在 c# 中宣告為 class 的結構(當 version_info 宣告為 class )

delegate void getversioninfo ( version_info ver);

如果結構宣告為 struct ,那麼應該使用如下宣告:

delegate void getversioninfo ( ref version_info ver);

注意:應該使用 ref 關鍵字。

如果 dll 函式需要傳入乙個字串,比如這樣:

bool __stdcall jingzhongrong1(constwchar_t* lpfilename, int * filenum);

那麼使用委託來呼叫函式的時候應該在 c# 中如下宣告委託:

delegatebooljingzhongrong1(

[marshalas(unmanagedtype.lpwstr)]string filename,

refint filenum);

注意:應該使用 [marshalas(unmanagedtype.lpwstr)] 和 string 進行宣告。

如果要在 dll 函式中傳出乙個字串,比如這樣:

void __stdcall jingzhongrong2(

wchar_t* lpfilename, // 要傳出的字串

int * length);

那麼我們如下宣告委託:

// 使用委託從非託管函式的引數中傳出的字串,

// 應該這樣宣告,並在呼叫前為 string builder 預備足夠的空間

delegatevoidjingzhongrong2(

[marshalas(unmanagedtype.lpwstr)] string builderlpfilename,

refint length,

); 在使用函式前,應先為 string builder 宣告足夠的空間用於存放字串:

string builder filename = new string builder(filenamelength);

C 動態呼叫C 編寫的DLL函式

動態載入dll需要使用windows api函式 loadlibrary getprocaddress以及freelibrary。我們可以使用dllimport在c 中使用這三個函式。dllimport kernel32 public static extern int getprocaddress...

C 呼叫C 編寫的dll

介面還是c 寫的方便點,主要是有乙個視覺化的編輯器,不想畫太多的時間在介面上。但是自己又對c 了解的多一些,所以在需要乙個良好的介面的情況下,使用c 來寫 邏輯,將其編譯成乙個dll,然後用c 寫介面,extern c declspec dllexport int testadd int a,int...

C 呼叫C 程式編寫的dll

c 呼叫c 程式編寫的dll 比起 c 呼叫c 程式編寫的dll要方便得多。假定我已經有個cplusplusdll.dll,此dll是用c 寫的,下面的程式是c 呼叫的程式。注意dll要放到c 工程的bin目錄下的debug目錄下。using system using system.collecti...