c#的dllimport使用方法詳解
DllImport是System.Runtime.InteropServices命名空間下的一個屬性類,其功能是提供從非托管DLL導(dǎo)出的函數(shù)的必要調(diào)用信息
DllImport屬性應(yīng)用于方法,要求最少要提供包含入口點(diǎn)的dll的名稱。
DllImport的定義如下:
[AttributeUsage(AttributeTargets.Method)]
public class DllImportAttribute: System.Attribute
{
public DllImportAttribute(string dllName) {…} //定位參數(shù)為dllName
public CallingConvention CallingConvention; //入口點(diǎn)調(diào)用約定
public CharSet CharSet; //入口點(diǎn)采用的字符接
public string EntryPoint; //入口點(diǎn)名稱
public bool ExactSpelling; //是否必須與指示的入口點(diǎn)拼寫完全一致,默認(rèn)false
public bool PreserveSig; //方法的簽名是被保留還是被轉(zhuǎn)換
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。 用此方式調(diào)用Win32API的數(shù)據(jù)類型對應(yīng):DWORD=int或uint,BOOL=bool,預(yù)定義常量=enum,結(jié)構(gòu)=struct。
DllImport會按照順序自動去尋找的地方: 1、exe所在目錄 2、System32目錄 3、環(huán)境變量目錄所以只需要你把引用的DLL 拷貝到這三個目錄下 就可以不用寫路徑了 或者可以這樣server.MapPath(.\bin\*.dll)web中的,同時也是應(yīng)用程序中的 后來發(fā)現(xiàn)用[DllImport(@"C:\OJ\Bin\Judge.dll")]這樣指定DLL的絕對路徑就可以正常裝載?!∵@個問題最常出現(xiàn)在使用第三方非托管DLL組件的時候,我的也同樣是這時出的問題,Asp.Net Team的官方解決方案如下: 首先需要確認(rèn)你引用了哪些組件,那些是托管的,哪些是非托管的.托管的很好辦,直接被使用的需要引用,間接使用的需要拷貝到bin目錄下.非托管的處理會比較麻煩.實(shí)際上,你拷貝到bin沒有任何幫助,因?yàn)镃LR會把文件拷貝到一個臨時目錄下,然后在那運(yùn)行web,而CLR只會拷貝托管文件,這就是為什么我們明明把非托管的dll放在了bin下卻依然提示不能加載模塊了. 具體做法如下: 首先我們在服務(wù)器上隨便找個地方新建一個目錄,假如為C:\DLL 然后,在環(huán)境變量中,給Path變量添加這個目錄 最后,把所有的非托管文件都拷貝到C:\DLL中. 或者更干脆的把DLL放到system32目錄 對于可以自己部署的應(yīng)用程序,這樣未償不是一個解決辦法,然而,如果我們用的是虛擬空間,我們是沒辦法把注冊PATH變量或者把我們自己的DLL拷到system32目錄的。同時我們也不一定知道我們的Dll的物理路徑?! llImport里面只能用字符串常量,而不能夠用Server.MapPath(@"~/Bin/Judge.dll")來確定物理路徑。ASP.NET中要使用DllImport的,必須在先“using System.Runtime.InteropServices;”不過,我發(fā)現(xiàn),調(diào)用這種"非托管Dll”相當(dāng)?shù)穆?,可能是因?yàn)槲业姆椒ㄐ枰h(yuǎn)程驗(yàn)證吧,但是實(shí)在是太慢了。經(jīng)過一翻研究,終于想到了一個完美的解決辦法首先我們用
[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進(jìn)行載入,最后用GetProcAddress取得要用的函數(shù)地址
以下自定義類的代碼完成LoadLibrary的裝載和函數(shù)調(diào)用
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ù)轉(zhuǎn)換為委托
public Delegate Invoke(String APIName,Type t)
{
IntPtr api = GetProcAddress(hLib, APIName);
return (Delegate)Marshal.GetDelegateForFunctionPointer(api,t);
}
}
下面代碼進(jìn)行調(diào)用
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);//這里就是調(diào)用我的DLL里定義的Compile函數(shù)
大家在實(shí)際工作學(xué)習(xí)C#的時候,可能會問:為什么我們要為一些已經(jīng)存在的功能(比如Windows中的一些功能,C++中已經(jīng)編寫好的一些方法)要重新編寫代碼,C#有沒有方法可以直接都用這些原本已經(jīng)存在的功能呢?答案是肯定的,大家可以通過C#中的DllImport直接調(diào)用這些功能。
DllImport所在的名字空間 using System.Runtime.InteropServices;
MSDN中對DllImportAttribute的解釋是這樣的:可將該屬性應(yīng)用于方法。DllImportAttribute 屬性提供對從非托管 DLL
導(dǎo)出的函數(shù)進(jìn)行調(diào)用所必需的信息。作為最低要求,必須提供包含入口點(diǎn)的 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ù):指定包含被導(dǎo)入方法的 dll 名稱的
dllName 參數(shù)。
3、DllImport具有五個命名參數(shù):
a、CallingConvention
參數(shù)指示入口點(diǎn)的調(diào)用約定。如果未指定 CallingConvention,則使用默認(rèn)值
CallingConvention.Winapi。
b、CharSet 參數(shù)指示用在入口點(diǎn)中的字符集。如果未指定 CharSet,則使用默認(rèn)值
CharSet.Auto。
c、EntryPoint 參數(shù)給出 dll 中入口點(diǎn)的名稱。如果未指定
EntryPoint,則使用方法本身的名稱。
d、ExactSpelling 參數(shù)指示 EntryPoint
是否必須與指示的入口點(diǎn)的拼寫完全匹配。如果未指定 ExactSpelling,則使用默認(rèn)值 false。
e、PreserveSig
參數(shù)指示方法的簽名應(yīng)當(dāng)被保留還是被轉(zhuǎn)換。當(dāng)簽名被轉(zhuǎn)換時,它被轉(zhuǎn)換為一個具有 HRESULT返回值和該返回值的一個名為 retval
的附加輸出參數(shù)的簽名。如果未指定 PreserveSig,則使用默認(rèn)值 true。
f、SetLastError 參數(shù)指示方法是否保留
Win32"上一錯誤"。如果未指定 SetLastError,則使用默認(rèn)值 false。
4、它是一次性屬性類。
5、此外,用 DllImport 屬性修飾的方法必須具有 extern 修飾符。
相關(guān)文章
C#中Foreach循環(huán)遍歷的本質(zhì)與枚舉器詳解
這篇文章主要給大家介紹了關(guān)于C#中Foreach循環(huán)遍歷本質(zhì)與枚舉器的相關(guān)資料,foreach循環(huán)用于列舉出集合中所有的元素,foreach語句中的表達(dá)式由關(guān)鍵字in隔開的兩個項組成,本文通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-08-08Winform使用DataGridView實(shí)現(xiàn)下拉篩選
這篇文章主要為大家詳細(xì)介紹了Winform如何使用原生DataGridView實(shí)現(xiàn)下拉篩選功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-09-09c# 如何使用結(jié)構(gòu)體實(shí)現(xiàn)共用體
這篇文章主要介紹了c# 如何使用結(jié)構(gòu)體實(shí)現(xiàn)共用體,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-04-04C# / VB.NET 在PPT中創(chuàng)建、編輯PPT SmartArt圖形的方法詳解
本文介紹通過C#和VB.NET程序代碼來創(chuàng)建和編輯PPT文檔中的SmartArt圖形。文中將分兩個操作示例來演示創(chuàng)建和編輯結(jié)果,需要的朋友可以參考下2020-10-10c#實(shí)現(xiàn)16進(jìn)制和字符串之間轉(zhuǎn)換的代碼
#中十六進(jìn)制字符串的轉(zhuǎn)換函數(shù)2007-05-05