[C#/C++]C#調用非托管DLL的APIs 上網(wǎng)baidu一下或google一下這個(gè)東東就有很多人在問(wèn)這個(gè)問(wèn)題,最近我也用到了這個(gè),所以就留下來(lái)以備往后需要是可以查找。我想通過(guò)這個(gè)來(lái)作為C#調用windows APIs的出發(fā)點(diǎn),在以后的隨筆當中介紹一下我現階段用到的一些APIs或非托管類(lèi)庫。在調用非托管DLL的APIs前,我們應該好好掌握一下DllImportAttribute,MSDN給出的定義為:可將該屬性應用于方法。DllImportAttribute 屬性提供對從非托管 DLL 導出的函數進(jìn)行調用所必需的信息。作為最低要求,必須提供包含入口點(diǎn)的 DLL 的名稱(chēng)。1 [DllImport("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true,2 3 CharSet=CharSet.Unicode, ExactSpelling=true,4 5 CallingConvention=CallingConvention.StdCall)]6 7 public static extern bool MoveFile(String src, String dst);8 9 從上面的例子中我們可以看出,從Kernel32.dll中引入這個(gè)API,其中EntryPoint一看就知道是入口點(diǎn),也就是DLL中的函數名稱(chēng)。其實(shí)只要用過(guò)VC++的人都知道,Windows APIs中都提供兩個(gè)版本,一個(gè)是W,一個(gè)是A也就是Ansi和Unicode之分,現在一般都采用W,Unicode編程,但是.Net和win32交互的時(shí)候,默認是使用CharSet.Ansi來(lái)傳送。在 DllImportAttribute.ExactSpelling 字段為 true 時(shí)(它是 Visual Basic .NET 中的默認值),平臺調用將只搜索您指定的名稱(chēng)。例如,如果指定 MessageBox,則平臺調用將搜索 MessageBox,如果它找不到完全相同的拼寫(xiě)則失敗。當 ExactSpelling 字段為 false(它是 C++ 托管擴展和 C# 中的默認值),平臺調用將首先搜索未處理的別名 (MessageBox),如果沒(méi)有找到未處理的別名,則將搜索已處理的名稱(chēng) (MessageBoxA)。 由于很多參數和C#中有所區別,下面讓我們看看參數是怎么個(gè)情況: extern “C” __declspec(dllexport) int WINAPI sumAB(int a,int b)這個(gè)和C#中一樣是值類(lèi)型,a及b的變化不會(huì )對C#中的參數造成影響。通過(guò)DllImport表示為:1 [DllImport(“CppDll.dll")]2 //返回個(gè)int 類(lèi)型3 public static extern int sumAB (int a1,int b1); 下面的是引用類(lèi)型:也就是說(shuō)a和b的變化直接影響到a1和b1的值。public static extern int sum (ref int a1,ref int b1);//DLL中申明extern “C” __declspec(dllexport) int WINAPI sum(int *a,int *b) 同理我們可以得到一下幾種傳值方法:第一種參數的改變不影響C#中參數的變化,需要傳入char*類(lèi)型。[DllImport(“CppDll.dll")]//傳入值public static extern int together (string astr,string bstr);//DLL中申明extern “C” __declspec(dllexport) int WINAPI together(char * stra,char * strb) 當我們需要從參數中傳出char*類(lèi)型是,那我們就要用到StringBuilder了。1 // 傳出值2 public static extern int getParameter (StringBuilder sb1, StringBuilder sb2);3 //DLL中申明4 extern “C” __declspec(dllexport) int WINAPI getParameter(char * stra,char * strb) 接著(zhù)我們先來(lái)看看結構的封送,這里我們要看看StructLayoutAttribute這個(gè)標簽,通過(guò)它可以定義自己的格式化類(lèi)型,在托管代碼中,格式化類(lèi)型是一個(gè)用StructLayoutAttribute說(shuō)明的結構或類(lèi)成員,通過(guò)它能夠保證其內部成員預期的布局信息,他的成員說(shuō)明如下: LayoutKind.Automatic 為了提高效率允許運行態(tài)對類(lèi)型成員重新排序。注意:永遠不要使用這個(gè)選項來(lái)調用非托管的動(dòng)態(tài)鏈接庫函數。 LayoutKind.Explicit 對每個(gè)域按照FieldOffset屬性對類(lèi)型成員排序 LayoutKind.Sequential 對出現在托管類(lèi)型定義地方的非托管內存中的類(lèi)型成員進(jìn)行排序。 我們可以通過(guò)GetSystemInfo來(lái)獲取系統的信息,代碼如下: 1 using System.Runtime.InteropServices; 2 [StructLayout(LayoutKind.Sequential)] 3 public struct SYSTEM_INFO { 4 public uint dwOemId; 5 public uint dwPageSize; 6 public uint lpMinimumApplicationAddress; 7 public uint lpMaximumApplicationAddress; 8 public uint dwActiveProcessorMask; 9 public uint dwNumberOfProcessors;10 public uint dwProcessorType;11 public uint dwAllocationGranularity;12 public uint dwProcessorLevel;13 public uint dwProcessorRevision;14 }15 //調用16 [DllImport("kernel32")]17 static extern void GetSystemInfo(ref SYSTEM_INFO pSI);18 SYSTEM_INFO pSI = new SYSTEM_INFO();19 GetSystemInfo(ref pSI); 當我們遇到函數指針參數是我們就需要考慮是否要用到回調函數,例如枚舉所有窗口。 BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam) 我們可以通過(guò)創(chuàng )建一個(gè)代理,它帶有兩個(gè)參數hwnd和lparam,第一個(gè)參數是一個(gè)窗口句柄,第二個(gè)參數由應用程序定義,兩個(gè)參數均為整形。當這個(gè)回調函數返回一個(gè)非零值時(shí),標示執行成功,零則暗示失敗,這個(gè)例子總是返回True值,以便持續枚舉。最后創(chuàng )建以代理對象(delegate),并把它作為一個(gè)參數傳遞給EnumWindows 函數,平臺會(huì )自動(dòng)地 把代理對象轉化成函數能夠識別的回調格式。 1 using System; 2 using System.Runtime.InteropServices; 3 public delegate bool CallBack(int hwnd, int lParam); 4 public class EnumReportApp { 5 [DllImport("user32")] 6 public static extern int EnumWindows(CallBack x, int y); 7 public static void Main() 8 { 9 CallBack myCallBack = new CallBack(EnumReportApp.Report);10 EnumWindows(myCallBack, 0);11 }12 public static bool Report(int hwnd, int lParam) {13 Console.Write("窗口句柄為");14 Console.WriteLine(hwnd);15 return true;16 }17 } OK,如果熟悉了以上方方面面,基本上也能夠調用APIs了別忘了P/Invoke能夠幫上很大的忙,我們可以去wiki網(wǎng)站查詢(xún)我們所要的API:http://pinvoke.net。還需要說(shuō)明的是很多例子等都來(lái)自MSDN和網(wǎng)上檢索得到的?。?!
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。