DllImport是System.Runtime.InteropServices命名空間下的一個屬性類骗卜,其功能是提供從非托管DLL導出的函數(shù)的必要調用信息
DllImport屬性應用于方法,要求最少要提供包含入口點的dll的名稱。
DllImport的定義如下:
[AttributeUsage(AttributeTargets.Method)]
public class DllImportAttribute: System.Attribute
{
public DllImportAttribute(string dllName) {…} //定位參數(shù)為dllName
public CallingConvention CallingConvention; //入口點調用約定
public CharSet CharSet;?????????????????????????????????? //入口點采用的字符接
public string EntryPoint;? //入口點名稱
public bool ExactSpelling;?? //是否必須與指示的入口點拼寫完全一致寇仓,默認false
public bool PreserveSig;? //方法的簽名是被保留還是被轉換
public bool SetLastError;? //FindLastError方法的返回值保存在這里
public string Value { get {…} }
}
用法示例:
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section,string key,string val,string filePath);
以上是用來寫入ini文件的一個win32api举户。????????? 用此方式調用Win32API的數(shù)據(jù)類型對應:DWORD=int或uint,BOOL=bool焚刺,預定義常量=enum敛摘,結構=struct。?
DllImport會按照順序自動去尋找的地方: 1乳愉、exe所在目錄 2兄淫、System32目錄 3、環(huán)境變量目錄所以只需要你把引用的DLL 拷貝到這三個目錄下 就可以不用寫路徑了 或者可以這樣server.MapPath(.\bin\*.dll)web中的蔓姚,同時也是應用程序中的 后來發(fā)現(xiàn)用[DllImport(@"C:\OJ\Bin\Judge.dll")]這樣指定DLL的絕對路徑就可以正常裝載捕虽。 這個問題最常出現(xiàn)在使用第三方非托管DLL組件的時候,我的也同樣是這時出的問題,Asp.Net Team的官方解決方案如下: 首先需要確認你引用了哪些組件,那些是托管的,哪些是非托管的.托管的很好辦,直接被使用的需要引用,間接使用的需要拷貝到bin目錄下.非托管的處理會比較麻煩.實際上,你拷貝到bin沒有任何幫助,因為CLR會把文件拷貝到一個臨時目錄下,然后在那運行web,而CLR只會拷貝托管文件,這就是為什么我們明明把非托管的dll放在了bin下卻依然提示不能加載模塊了. 具體做法如下: 首先我們在服務器上隨便找個地方新建一個目錄,假如為C:\DLL 然后,在環(huán)境變量中,給Path變量添加這個目錄 最后,把所有的非托管文件都拷貝到C:\DLL中. 或者更干脆的把DLL放到system32目錄 對于可以自己部署的應用程序坡脐,這樣未償不是一個解決辦法泄私,然而,如果我們用的是虛擬空間备闲,我們是沒辦法把注冊PATH變量或者把我們自己的DLL拷到system32目錄的晌端。同時我們也不一定知道我們的Dll的物理路徑√裆埃 DllImport里面只能用字符串常量咧纠,而不能夠用Server.MapPath(@"~/Bin/Judge.dll")來確定物理路徑。ASP.NET中要使用DllImport的泻骤,必須在先“using System.Runtime.InteropServices;”不過漆羔,我發(fā)現(xiàn),調用這種"非托管Dll”相當?shù)穆啵赡苁且驗槲业姆椒ㄐ枰h程驗證吧演痒,但是實在是太慢了。經過一翻研究趋惨,終于想到了一個完美的解決辦法首先我們用
[DllImport("kernel32.dll")]
private extern static IntPtr LoadLibrary(String path);
[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);
[DllImport("kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);
分別取得了LoadLibrary和GetProcAddress函數(shù)的地址鸟顺,再通過這兩個函數(shù)來取得我們的DLL里面的函數(shù)。
我們可以先用Server.MapPath(@"~/Bin/Judge.dll")來取得我們的DLL的物理路徑希柿,然后再用LoadLibrary進行載入诊沪,最后用GetProcAddress取得要用的函數(shù)地址
以下自定義類的代碼完成LoadLibrary的裝載和函數(shù)調用
public class DllInvoke
??? {???????????
??????? [DllImport("kernel32.dll")]
??????? private extern static IntPtr LoadLibrary(String path);
??????? [DllImport("kernel32.dll")]??
??????? private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);
??????? [DllImport("kernel32.dll")]????
??????? private extern static bool FreeLibrary(IntPtr lib);????
??????? private IntPtr hLib;??
??????? public DllInvoke(String DLLPath)??
??????? {??????????
??????????? hLib = LoadLibrary(DLLPath);?
??????? }??????
??????? ~DllInvoke()????
??????? {???????
??????????? FreeLibrary(hLib);?
??????? }???????
??????? //將要執(zhí)行的函數(shù)轉換為委托?
??????? public Delegate Invoke(String APIName,Type t)????
??????? {??????????
??????????? IntPtr api = GetProcAddress(hLib, APIName);??
??????????? return (Delegate)Marshal.GetDelegateForFunctionPointer(api,t);????
??????? }
??? }
下面代碼進行調用
public delegate int Compile(String command, StringBuilder inf);
??????????? //編譯
??????????? DllInvoke dll = new DllInvoke(Server.MapPath(@"~/Bin/Judge.dll"));
??????????? Compile compile = (Compile)dll.Invoke("Compile", typeof(Compile));
??????????? StringBuilder inf;
??????????? compile(@“gcc a.c -o a.exe“,inf);//這里就是調用我的DLL里定義的Compile函數(shù)
大家在實際工作學習C#的時候,可能會問:為什么我們要為一些已經存在的功能(比如Windows中的一些功能曾撤,C++中已經編寫好的一些方法)要重新編寫代碼端姚,C#有沒有方法可以直接都用這些原本已經存在的功能呢?答案是肯定的挤悉,大家可以通過C#中的DllImport直接調用這些功能渐裸。???
DllImport所在的名字空間 using System.Runtime.InteropServices;???
MSDN中對DllImportAttribute的解釋是這樣的:可將該屬性應用于方法巫湘。DllImportAttribute 屬性提供對從非托管 DLL
導出的函數(shù)進行調用所必需的信息。作為最低要求昏鹃,必須提供包含入口點的 DLL 的名稱尚氛。??? DllImport 屬性定義如下:
namespace System.Runtime.InteropServices??
?{??
???? [AttributeUsage(AttributeTargets.Method)]??
???? public class DllImportAttribute: System.Attribute?
???? {??
???????? public DllImportAttribute(string dllName)
???????? {...}??
???????? public CallingConvention CallingConvention;??
???????? public CharSet CharSet;??
???????? public string EntryPoint;??
???????? public bool ExactSpelling;??
???????? public bool PreserveSig;??
???????? public bool SetLastError;??
???????? public string Value { get {...} }??
???? }??
?}
說明:????
1、DllImport只能放置在方法聲明上洞渤。
2阅嘶、DllImport具有單個定位參數(shù):指定包含被導入方法的 dll 名稱的
dllName 參數(shù)。????
3载迄、DllImport具有五個命名參數(shù):?
a讯柔、CallingConvention
參數(shù)指示入口點的調用約定。如果未指定 CallingConvention护昧,則使用默認值
CallingConvention.Winapi魂迄。
b、CharSet 參數(shù)指示用在入口點中的字符集惋耙。如果未指定 CharSet捣炬,則使用默認值
CharSet.Auto。????
c绽榛、EntryPoint 參數(shù)給出 dll 中入口點的名稱湿酸。如果未指定
EntryPoint,則使用方法本身的名稱灭美。?????
d稿械、ExactSpelling 參數(shù)指示 EntryPoint
是否必須與指示的入口點的拼寫完全匹配。如果未指定 ExactSpelling冲粤,則使用默認值 false。?????
e页眯、PreserveSig
參數(shù)指示方法的簽名應當被保留還是被轉換梯捕。當簽名被轉換時,它被轉換為一個具有 HRESULT返回值和該返回值的一個名為 retval
的附加輸出參數(shù)的簽名窝撵。如果未指定 PreserveSig傀顾,則使用默認值 true。?????
f碌奉、SetLastError 參數(shù)指示方法是否保留
Win32"上一錯誤"短曾。如果未指定 SetLastError,則使用默認值 false赐劣。?????
4嫉拐、它是一次性屬性類。?????
5魁兼、此外婉徘,用 DllImport 屬性修飾的方法必須具有 extern 修飾符。