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

2021-12-29 16:30:39 字數 4197 閱讀 2799

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

[dllimport("kernel32")]

public static extern int getprocaddress(int handle, string funcname);

[dllimport("kernel32")]

public static extern int loadlibrary(string funcname);

[dllimport("kernel32")]

public static extern int freelibrary(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);

3、呼叫getprocaddress函式獲取要呼叫函式的位址:

pfoo foo = (pfoo)getprocaddress(hinst,"foo");

if(foo == null)

4、呼叫foo函式:

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

5、使用完後應釋放dll:

freelibrary(hinst);

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

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

public class dllwrapper

///

///將表示函式位址的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:

int hmodule = dllwrapper.loadlibrary(dllfilepath);

if (hmodule == 0)

return false;

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

foo foo = (foo)dllwrapper.getfunctionaddress(hmodule, "foo", typeof(foo));

if (foo == null)

4、呼叫函式:

foo(...);

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

dllwrapper.freelibrary(hmodule);

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

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

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

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

[structlayout(layoutkind.sequential)]

struct structversioninfo

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

[structlayout(layoutkind.sequential)]

class structversioninfo

對應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# publicstructversioninfo ver;

c++:函式指標宣告

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

c#:

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

//不同的宣告方法可以使用上面dllwrapper類的相應函式獲取對應的委託例項

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

3、委託的宣告:

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

void getversioninfo(version_info *ver);

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

delegate voidgetversioninfo(version_info ver);

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

delegate voidgetversioninfo(refversion_info ver);

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

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

bool __stdcall jingzhongrong1(const wchar_t* lpfilename, int* filenum);

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

delegate bool jingzhongrong1(

[marshalas(unmanagedtype.lpwstr)]string filename,

ref int filenum);

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

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

void __stdcall jingzhongrong2(

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

int* length);

那麼我們如下宣告委託:

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

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

delegate void jingzhongrong2(

[marshalas(unmanagedtype.lpwstr)] stringbuilder lpfilename,

ref int length,

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

stringbuilder filename = new stringbuilder(filenamelength);

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

c 動態呼叫c 編寫的dll函式 c 動態呼叫c 編寫的dll函式 動態載入 dll 需要使用 windows api 函式 loadlibrary getprocaddress 以及 freelibrary 我們可以使用 dllimport 在 c 中使用這三個函式。dllimport kerne...

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...