這是三篇網上收集的技術文章的合集,分別講解了如何創建win32 dll,然后如何在c#里面調用這個dll的教程。
首先是創建win32 dll的文章。講解這個的文章到處都有,這里給出一篇我看過的:http://www.flipcode.com/articles/article_creatingdlls.shtml。win32 dll的創建其實在visual studio里面已經給出了比較好的模板,只是需要注意的,有些xxx_api宏并沒有把extern "c"加進去,這樣會造成在c#里面找不到這個函數的錯誤。所以,請記住,一定要把函數定義extern "c"。
第二篇文章來之于http://edu.100down.com/it/program/csharp/105256797.html,下面是轉貼內容:
平臺調用服務 (pinvoke) 允許托管代碼調用在 dll 中實現的非托管函數。
本教程說明使用什么方法才能從 c# 調用非托管 dll 函數。該教程所討論的屬性允許您調用這些函數并使數據類型得到正確封送。
c# 代碼有以下兩種可以直接調用非托管代碼的方法:
對于這兩種技術,都必須向 c# 編譯器提供非托管函數的聲明,并且還可能需要向 c# 編譯器提供如何封送與非托管代碼之間傳遞的參數和返回值的說明。
該教程由下列主題組成:
該教程包括下列示例:
若要聲明一個方法使其具有來自 dll 導出的實現,請執行下列操作:
本示例顯示如何使用 dllimport 屬性通過調用 msvcrt.dll 中的 puts 輸出消息。
// pinvoketest.csusing system;using system.runtime.interopservices;class platforminvoketest{ [dllimport("msvcrt.dll")] public static extern int puts(string c); [dllimport("msvcrt.dll")] internal static extern int _flushall(); public static void main() { puts("test"); _flushall(); }}test
前面的示例顯示了聲明在非托管 dll 中實現的 c# 方法的最低要求。platforminvoketest.puts 方法用 static 和 extern 修飾符聲明并且具有 dllimport 屬性,該屬性使用默認名稱 puts 通知編譯器此實現來自 msvcrt.dll。若要對 c# 方法使用不同的名稱(如 putstring),則必須在 dllimport 屬性中使用 entrypoint 選項,如下所示:
[dllimport("msvcrt.dll", entrypoint="puts")]有關 dllimport 屬性的語法的更多信息,請參見 dllimportattribute 類。
當從 c# 代碼中調用非托管函數時,公共語言運行庫必須封送參數和返回值。
對于每個 .net framework 類型均有一個默認非托管類型,公共語言運行庫將使用此非托管類型在托管到非托管的函數調用中封送數據。例如,c# 字符串值的默認封送處理是封送為 lptstr(指向 tchar 字符緩沖區的指針)類型。可以在非托管函數的 c# 聲明中使用 marshalas 屬性重寫默認封送處理。
本示例使用 dllimport 屬性輸出一個字符串。它還顯示如何通過使用 marshalas 屬性重寫函數參數的默認封送處理。
// marshal.csusing system;using system.runtime.interopservices;class platforminvoketest{ [dllimport("msvcrt.dll")] public static extern int puts( [marshalas(unmanagedtype.lpstr)] string m); [dllimport("msvcrt.dll")] internal static extern int _flushall(); public static void main() { puts("hello world!"); _flushall(); }}運行此示例時,字符串
hello world!
將顯示在控制臺上。
在前面的示例中,puts 函數的參數的默認封送處理已從默認值 lptstr 重寫為 lpstr。
marshalas 屬性可以放置在方法參數、方法返回值以及結構和類的字段上。若要設置方法返回值的封送處理,請將 marshalas 屬性與返回屬性位置重寫一起放置在方法上的屬性塊中。例如,若要顯式設置 puts 方法返回值的封送處理:
...[dllimport("msvcrt.dll")] [return : marshalas(unmanagedtype.i4)]public static extern int puts( ...有關 marshalas 屬性的語法的更多信息,請參見 marshalasattribute 類。
注意 in 和 out 屬性可用于批注非托管方法的參數。它們與 midl 源文件中的 in 和 out 修飾符的工作方式類似。請注意,out 屬性與 c# 參數修飾符 out 不同。有關 in 和 out 屬性的更多信息,請參見 inattribute 類和 outattribute 類。
可以為傳遞到非托管函數或從非托管函數返回的結構和類的字段指定自定義封送處理屬性。通過向結構或類的字段中添加 marshalas 屬性可以做到這一點。還必須使用 structlayout 屬性設置結構的布局,還可以控制字符串成員的默認封送處理,并設置默認封裝大小。
本示例說明如何為結構指定自定義封送處理屬性。
請考慮下面的 c 結構:
typedef struct taglogfont { long lfheight; long lfwidth; long lfescapement; long lforientation; long lfweight; byte lfitalic; byte lfunderline; byte lfstrikeout; byte lfcharset; byte lfoutprecision; byte lfclipprecision; byte lfquality; byte lfpitchandfamily; tchar lffacename[lf_facesize]; } logfont; 在 c# 中,可以使用 structlayout 和 marshalas 屬性描述前面的結構,如下所示:
// logfont.cs// compile with: /target:moduleusing system;using system.runtime.interopservices;[structlayout(layoutkind.sequential)]public class logfont { public const int lf_facesize = 32; public int lfheight; public int lfwidth; public int lfescapement; public int lforientation; public int lfweight; public byte lfitalic; public byte lfunderline; public byte lfstrikeout; public byte lfcharset; public byte lfoutprecision; public byte lfclipprecision; public byte lfquality; public byte lfpitchandfamily; [marshalas(unmanagedtype.byvaltstr, sizeconst=lf_facesize)] public string lffacename; }有關 structlayout 屬性的語法的更多信息,請參見 structlayoutattribute 類。
然后即可將該結構用在 c# 代碼中,如下所示:
// pinvoke.cs// compile with: /addmodule:logfont.netmoduleusing system;using system.runtime.interopservices; class platforminvoketest{ [dllimport("gdi32.dll", charset=charset.auto)] public static extern intptr createfontindirect( [in, marshalas(unmanagedtype.lpstruct)] logfont lplf // characteristics ); [dllimport("gdi32.dll")] public static extern bool deleteobject( intptr handle ); public static void main() { logfont lf = new logfont(); lf.lfheight = 9; lf.lffacename = "arial"; intptr handle = createfontindirect(lf); if (intptr.zero == handle) { console.writeline("can't creates a logical font."); } else { if (intptr.size == 4) console.writeline("{0:x}", handle.toint32()); else console.writeline("{0:x}", handle.toint64()); // delete the logical font created. if (!deleteobject(handle)) console.writeline("can't delete the logical font"); } }}c30a0ae5
在前面的示例中,createfontindirect 方法使用了一個 logfont 類型的參數。marshalas 和 in 屬性用于限定此參數。程序將由此方法返回的數值顯示為十六進制大寫字符串。
若要注冊調用非托管函數的托管回調,請用相同的參數列表聲明一個委托并通過 pinvoke 傳遞它的一個實例。在非托管端,它將顯示為一個函數指針。有關 pinvoke 和回調的更多信息,請參見平臺調用詳解。
例如,考慮以下非托管函數 myfunction,此函數要求 callback 作為其參數之一:
typedef void (__stdcall *pfn_mycallback)();int __stdcall myfunction(pfn_ mycallback callback);
若要從托管代碼調用 myfunction,請聲明該委托,將 dllimport 附加到函數聲明,并根據需要封送任何參數或返回值:
public delegate void mycallback();[dllimport("mydll.dll")]public static extern void myfunction(mycallback callback);同時,請確保委托實例的生存期覆蓋非托管代碼的生存期;否則,委托在經過垃圾回收后將不再可用。
第三篇文章來之于http://www.njpro.cn/8918/showpost.aspx,一篇關于c/c++和c#中的數據類型的對應表。
| wtypes.h 中的非托管類型 | 非托管 c 語言類型 | 托管類名 | 說明 |
|---|---|---|---|
| handle | void* | 32 位 | |
| byte | unsigned char | 8 位 | |
| short | short | 16 位 | |
| word | unsigned short | 16 位 | |
| int | int | 32 位 | |
| uint | unsigned int | 32 位 | |
| long | long | 32 位 | |
| bool | long | 32 位 | |
| dword | unsigned long | 32 位 | |
| ulong | unsigned long | 32 位 | |
| char | char | 用 ansi 修飾。 | |
| lpstr | char* | 用 ansi 修飾。 | |
| lpcstr | const char* | 用 ansi 修飾。 | |
| lpwstr | wchar_t* | 用 unicode 修飾。 | |
| lpcwstr | const wchar_t* | 用 unicode 修飾。 | |
| float | float | 32 位 | |
| double | double |
新聞熱點
疑難解答