1,什么是dll文件?
DLL(Dynamic Link Library)文件為動態鏈接庫文件,又稱“應用程序拓展”,是軟件文件類型。在Windows中,許多應用程序並不是一個完整的可執行文件,它們被分割成一些相對獨立的動態鏈接庫,即DLL文件,放置於系統中。當我們執行某一個程序時,相應的DLL文件就會被調用。一個應用程序可使用多個DLL文件,一個DLL文件也可能被不同的應用程序使用,這樣的DLL文件被稱為共享DLL文件。
2,托管dll和非托管dll區別是什么?
托管DLL就是能夠在公共語言運行庫(Common Language Runtime,簡稱CLR)中能夠直接引用的,並且擴展為“DLL”的文件。具體所指就是封裝各種命名空間所在的DLL文件,如System.dll等。非托管DLL就是平常所的動態鏈接庫等,其中就包括了封裝所有Windows API函數的DLL文件。各種非托管DLL中的函數在公共語言運行庫中不能直接被調用,而需要經過.Net框架提供的“平台調用”服務后才可以。(簡而言之就是.net環境下生成的動態鏈接庫為托管dll,相反則為非托管dll)
3,托管dll和非托管dll如何使用?
托管dll在VS環境下使用相對容易,可以在項目名上右擊選擇添加應用的方式導入dll,本文這里不作詳解。非托管dll的使用步驟及如下:
1,需要檢查使用的dll的目標平台(Any Cpu,x86,x64),在項目屬性生成選項卡中選擇與dll相對應的目標平台。因為托管dll是在.net的環境下生成的,轉換為機器語言后能夠自動識別目標平台即有框架支持解釋,而非托管不能夠自己識別需要人為的設置。
2,使用DllImport導入非托管dll。
DllImport會按照以下3種順序查找dll文件:1)、exe所在目錄;
2)、System32目錄(系統目錄);
3)、環境變量目錄。(即需要將dll及依賴文件放到3個目錄中的任何一個目錄中)。
DllImport的導入規則:1)、方法名與Win API完全一樣。如果在C#中調用時顯示完全不同的方法名稱,則需要引入EntryPoint屬性,使用別名顯示。
2)、函數除需要DllImport類修飾符外,還需要聲明public static extern類型。
3)、函數返回值和參數必須和調用的API的完全一樣。
4)、必須引入System.Runtime.InteropServices命名空間。
DllImport的可選屬性參數說明:EntryPoint 指定要調用的 DLL 入口點。
SetLastError 判斷在執行該方法時是否出錯(使用 Marshal.GetLastWin32Error API 函數來確定)。C#中默認值為 false。
CharSet 控制名稱及函數中字符串參數的編碼方式。默認值為 CharSet.Ansi。
ExactSpelling 是否修改入口點以對應不同的字符編碼方式。
CallingConvention 指定用於傳遞方法參數的調用約定。默認值為 WinAPI。該值對應於基於32位Intel平台的 __stdcall。
BestFitMapping 是否啟用最佳映射功能,默認為 true。最佳映射功能提供在沒有匹配項時,自動提供匹配的字符。無法映射的字符通常轉換為默認的“?”。
PreserveSig 托管方法簽
名是否轉換成返回 HRESULT,默認值為 true(不應轉換簽名)。並且返回值有一個附加的 [out, retval] 參數的非托管簽名。
ThrowOnUnmappableChar 控制對轉換為 ANSI '?' 字符的不可映射的 Unicode 字符引發異常。
4,c#與c++、c動態鏈接庫的參數如何對應?
C C# 備注
short int16 短整型
int int32 整型
long int64 長整型
& ref 取地址
* ref 指針
c#中修飾符ref、out的作用及功能
ref 要求參數在傳遞給函數前要初始化,out則不需要,常見於平台調用中。out和ref傳遞的都是引用而不是值,out側重於輸出使用之前不需賦值而ref在使用之前需要賦值,另外這兩個關鍵字可以變相實現使一個方法輸出多個值。ref可以把參數的數值傳遞進函數,但是out是要把參數清空,就是說你無法把一個數值從out傳遞進去的,out進去后,參數的數值為空,所以你必須初始化一次。這個就是兩個的區別,或者說就像有的網友說的,ref是有進有出,out是只出不進。說明是引用的傳遞。
example:
//命名空間
using System.Runtime.InteropServices;
//導入非托管dll
//分配的庫處理和連接到數控指定的IP地址或主機名。
[DllImport("Fwlib64.dll", EntryPoint = "cnc_allclibhndl3", CallingConvention=CallingConvention.Cdecl)]
//short (const char *ipaddr, unsigned short port, long timeout, unsigned short *FlibHndl)
private static extern Int16 cnc_allclibhndl3(ref String ip, UInt16 port, Int64 timeout, ref UInt16 flibHndl);