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