當你寫久了應用層代碼,是不是需要來玩一下硬體呀?
這個時候你就會接觸到一些美妙的dll,比如
user32.dll
,
kernal32.dll
當然這些是非托管的代碼,我們在.net中無法直接使用,是以我們會需要使用PInvoke進行調用
于是你會使用
DllImport
特性标記一個方法,引入非托管函數
比如 我們希望彈出一個消息框,就會使用下面這個函數,添加
DllImport
特性,表明從哪個dll引入方法
public class Win32
{
[DllImport("user32.dll")]
public static extern IntPtr MessageBox(int hWnd, String text, String caption, uint type);
}
class Program
{
static void Main(string[] args)
{
Win32.MessageBox(0, "這是我的部落格:https://xinyuehtx.github.io/", "Hello 黃騰霄", 0);
Console.ReadLine();
}
}
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90zdNlXREVGModUZwgmMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL0YTMzQTMzkDM1EjMwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
不要被這些表象給騙了,哪有說的這麼簡單。
我們看一下MessageBox 的原始簽名
如果你像我這樣沒怎麼寫過c++,第一感覺一定是一臉懵逼,除了int和uint其他啥也沒看懂。
是以我們一步步來看如何将c++的MessageBox轉化為我們C#中的簽名
手把手PInvoke
- 首先打開Programming reference for Windows API -Microsoft Docs,找到目标函數
的介紹MessageBox
- 我們可以在
的DLL欄中看到Requirements
,這個就是我們在User32.dll
中所需要的dll的名稱DllImport
這樣為我們就可以寫出(其中?代表還未填寫的内容)
public class Win32
{
[DllImport("user32.dll")]
public static extern ? MessageBox(?);
}
- 接着我們從
中找到函數簽名Syntax
- 這裡比較麻煩的是4個參數的需要轉換為對應的托管類型,有時候還會涉及一些結構體和指針。
這裡我們先看一下
Parameters
第一個是一個
HWND
類型,表示一個視窗句柄,
可以通過
HWND
=Handle to A Window來記憶
那麼在c#中我們可以使用
Intptr
類型,表示一個指針或者句柄
第2,3個參數都是
LPCTSTR
LPCTSTR
= Long Pointer to a Const TCHAR String 是以這是一個字元串,我們此處使用
string
最後一個是
UINT
,我們直接在c#中有對應的
uint
這麼一看是不是就更加能夠了解了呢。
實操
再來一個簡單的例子,我們期望擷取HID裝置的接口GUID
方法給到你們,是HidD_GetHidGuid
先看requirements.txt,發現DLL 是
Hid.dll
接着是簽名和參數,
LPGUID
我們沒有提過,看解釋這邊是指向GUID的一個指針,是以我們使用
Guid
這個類型
是以我們現在得到的結果如下
[DllImport("hid.dll")]
public static extern void HidD_GetHidGuid(Guid hidGuid);
不過注意,我們WindowsApi中簽名的參數類型是一個指針,現在我們傳遞的
Guid
隻是一個結構體
是以我們還需要将其以
引用
方式傳遞,通過添加
ref
是以最終形式就是
[DllImport("hid.dll")]
public static extern void HidD_GetHidGuid(ref Guid hidGuid);
var guid = Guid.Empty;
Win32.HidD_GetHidGuid(ref guid);
Console.WriteLine(guid);
運作可以看到結果如下
Tip
有同學說,這麼說完了,我還是擔心會寫錯怎麼辦
沒關系,這裡給大家推薦一個網站pinvoke.net: the interop wiki!,裡面聚集了各種pinvoke的寫法,如果不清楚怎麼使用,可以去其中檢視
另外vs也帶有pinvoke的插件,使用方法可以參見呂毅同學的部落格使用 PInvoke.net Visual Studio Extension 輔助編寫 Win32 函數簽名 - walterlv
參考連結:
- pinvoke.net: the interop wiki!
- Platform Invoke Examples - Microsoft Docs
- Passing Structures -Microsoft Docs
- 使用 PInvoke.net Visual Studio Extension 輔助編寫 Win32 函數簽名 - walterlv
- MessageBox function - Microsoft Docs
- Programming reference for Windows API - Microsoft Docs
- HidD_GetHidGuid function (hidsdi.h) - Windows drivers 0 - Microsoft Docs
本文會經常更新,請閱讀個人部落格原文: https://xinyuehtx.github.io/ ,以避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
本作品采用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協定 進行許可。歡迎轉載、使用、重新釋出,但務必保留文章署名黃騰霄(包含連結: https://xinyuehtx.github.io/ ),不得用于商業目的,基于本文修改後的作品務必以相同的許可釋出。如有任何疑問,請 與我聯系 。