如何撰寫您的第一個 USB 用戶端驅動程式 (UMDF)
在本文中,您將使用 Microsoft Visual Studio 2022 所提供的使用者模式驅動程式、USB(UMDF V2) 範本來撰寫使用者模式驅動程序架構 (UMDF)型用戶端驅動程式。 建置並安裝客戶端驅動程序之後,您會在 裝置管理員 中檢視用戶端驅動程式,並在調試程式中檢視驅動程序輸出。
UMDF(本文中稱為架構)是以元件物件模型 (COM) 為基礎。 根據預設,每個架構對象都必須實作 IUnknown 及其方法 QueryInterface、AddRef 和 Release。 AddRef 和 Release 方法會管理物件的存留期,因此客戶端驅動程式不需要維護參考計數。 QueryInterface 方法可讓用戶端驅動程式取得 Windows Driver Frameworks (WDF) 物件模型中其他架構物件的介面指標。 架構物件會執行複雜的驅動程式工作,並與 Windows 互動。 某些架構物件會公開可讓客戶端驅動程式與架構互動的介面。
UMDF 型用戶端驅動程式會實作為同進程 COM 伺服器 (DLL),C++是撰寫 USB 裝置用戶端驅動程式的慣用語言。 一般而言,客戶端驅動程式會實作架構公開的數個介面。 本文是指將架構介面實作為回呼類別的用戶端驅動程式定義類別。 具現化這些類別之後,產生的回呼物件會與特定架構物件合作。 此合作關係可讓客戶端驅動程式有機會回應架構所報告的裝置或系統相關事件。 每當 Windows 向架構通知特定事件時,如果有可用的事件,架構就會叫用用戶端驅動程式的回呼。 否則,架構會繼續進行事件的默認處理。 範本程式代碼會定義驅動程式、裝置和佇列回呼類別。
如需範本所產生原始程式碼的說明,請參閱 瞭解 USB 用戶端驅動程式的 UMDF 範本程式碼。
在您開始使用 Intune 之前
若要開發、偵錯及安裝使用者模式驅動程式,您需要兩部計算機:
- 執行 Windows 10 或更新版本的 Windows 作業系統的主電腦。 主計算機是您開發環境,您可以在其中撰寫和偵錯驅動程式。
- 執行您要測試驅動程式版本的目標計算機,例如 Windows 11 版本 22H2。 目標電腦具有您想要偵錯的使用者模式驅動程式,以及其中一個調試程式。
在某些情況下,主計算機和目標計算機執行相同版本的 Windows,您只能有一部執行 Windows 10 或更新版本的 Windows 計算機。 本文假設您使用兩部計算機來開發、偵錯及安裝您的使用者模式驅動程式。
開始之前,請確定您符合下列需求:
軟體需求
主電腦具有 Visual Studio 2022。
您的主電腦具有適用於 Windows 11 版本 22H2 的最新 Windows 驅動程式套件 (WDK)。
套件包含標頭、連結庫、工具、檔,以及開發、建置和偵錯 USB 用戶端驅動程式所需的偵錯工具。 您可以從如何取得 WDK 的最新版本。
主電腦具有適用於 Windows 的最新版本偵錯工具。 您可以從 WDK 取得最新版本,也可以 下載並安裝適用於 Windows 的偵錯工具。
如果您使用兩部計算機,則必須設定主計算機和目標計算機以進行使用者模式偵錯。 如需詳細資訊,請參閱 在Visual Studio中設定使用者模式偵錯。
硬體需求
取得您將為其撰寫用戶端驅動程式的 USB 裝置。 在大部分情況下,您會提供USB裝置及其硬體規格。 此規格描述裝置功能和支援的廠商命令。 使用規格來判斷 USB 驅動程式的功能,以及相關的設計決策。
如果您不熟悉 USB 驅動程式開發,請使用 OSR USB FX2 學習套件 來研究 WDK 隨附的 USB 範例。 其中包含 USB FX2 裝置,以及實作用戶端驅動程式所需的所有硬體規格。
建議的閱讀資料
- 適用於所有驅動程式開發人員的概念
- 裝置節點和裝置堆疊
- 在 Windows 上開始使用驅動程式
- 使用者模式驅動程序架構
- 使用 Windows Driver Foundation 開發驅動程式,由 Penny Orwick 和 Guy Smith 撰寫。 如需詳細資訊,請參閱 使用WDF開發驅動程式。
步驟 1:產生驅動程式程式代碼
如需撰寫 UMDF 驅動程式程式代碼的詳細資訊,請參閱 根據範本撰寫 UMDF 驅動程式。
針對 USB 特定程式代碼,在 Visual Studio 2022 中選取下列選項
- 在 [ 新增專案 ] 對話框的頂端搜尋方塊中,輸入 USB。
- 在中間窗格中,選取 [使用者模式驅動程式]、[USB][UMDF V2]。
- 選取 [下一步]。
- 輸入專案名稱、選擇儲存位置,然後選取 [ 建立]。
下列螢幕快照顯示 USB 使用者模式驅動程式範本的 [新增專案] 對話方塊。
本文假設專案的名稱MyUSBDriver_UMDF_。 其包含下列檔案:
檔案 | 描述 |
---|---|
Driver.h;Driver.c | 包含驅動程式模組進入點的實作。 DriverEntry 和 WDFDRIVER 相關功能和回呼。 |
Device.h;Device.c | WDFDEVICE 和 WDFUSBDEVICE 相關功能和回呼。 |
Queue.h;Queue.c | WDFQUEUE 相關功能和回呼。 |
Trace.h | 定義裝置介面 GUID。 它也會宣告追蹤函式和巨集。 |
<項目名稱>.inf | 在目標電腦上安裝客戶端驅動程式所需的 INF 檔案。 |
步驟 2:新增裝置的相關信息
在建置驅動程式之前,您必須新增裝置的相關信息,特別是硬體標識碼。 若要提供硬體識別碼:
- 在 [方案總管] 視窗中,以滑鼠右鍵按兩下MyUSBDriver_UMDF_,然後選擇 [屬性]。
- 在 [ MyUSBDriver_UMDF_屬性頁] 視窗中,移至 [ 設定屬性 > 驅動程序安裝 > 部署],如下所示。
- 在部署之前,請先檢查移除先前的驅動程式版本。
- 針對 [ 目標裝置名稱],選取您為測試和偵錯設定的計算機名稱。
- 選取 [硬體標識符驅動程式更新],然後輸入驅動程式的硬體識別碼。 在此練習中,硬體標識碼為 Root\MyUSBDriver_UMDF_。 選取 [確定]。
注意
在此練習中,硬體標識碼不會識別實際的硬體片段。 它會將裝置樹狀結構中的位置識別為根節點子節點的虛構裝置。 針對實際硬體,請勿選取 [硬體標識符驅動程式更新]。 請改為選取 [ 安裝和驗證]。 您可以在驅動程式的資訊 (INF) 檔案中看到硬體識別碼。 在 [方案總管] 視窗中,移至 [MyUSBDriver_UMDF_>驅動程序檔案],然後按兩下 MyUSBDriver_UMDF_.inf。 硬體標識碼位於 [Standard.NT$ARCH$]。
所有UMDF型USB用戶端驅動程式都需要兩個Microsoft提供的驅動程式:反映器和 WinUSB。
反映器:如果您的驅動程式成功載入,反映器會載入為核心模式堆疊中最上層的驅動程式。 反映器必須是核心模式堆疊中的最上層驅動程式。 為了符合此需求,範本的 INF 檔案會將反映器指定為服務,並將 WinUSB 指定為 INF 中的較低篩選驅動程式:
[MyDevice_Install.NT.Services] AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall ; flag 0x2 sets this as the service for the device AddService=WinUsb,0x000001f8,WinUsb_ServiceInstall ; this service is installed because its a filter.
WinUSB:安裝套件必須包含適用於 Winusb.sys 的 cointallers,因為對於用戶端驅動程式,WinUSB 是核心模式 USB 驅動程式堆棧的閘道。 載入的另一個元件是客戶端驅動程式主機進程中名為 WinUsb.dll 的使用者模式 DLL(Wudfhost.exe)。 Winusb.dll會 公開 WinUSB 函式 ,以簡化用戶端驅動程式與 WinUSB 之間的通訊程式。
步驟 3:建置 USB 用戶端驅動程式程式代碼
若要建置驅動程式:
- 在 Visual Studio 2022 中開啟驅動程式專案或方案。
- 以滑鼠右鍵按兩下 方案總管中的方案,然後選取 [組態管理員]。
- 從 Configuration Manager 中,選取您的作用中解決方案組態(例如偵錯或發行),以及對應至您感興趣的組建類型的作用中解決方案平臺(例如 x64)。
- 確認您的裝置介面 GUID 在整個專案中都正確無誤。
- 裝置介面 GUID 定義於 Trace.h 中,並從 Device.c 中參考
MyUSBDriverUMDFCreateDevice
。 當您使用名稱MyUSBDriver_UMDF_建立專案時,Visual Studio 2022 會使用名稱GUID_DEVINTERFACE_MyUSBDriver_UMDF_
定義裝置介面 GUID,但使用不正確的參數&GUID_DEVINTERFACE_MyUSBDriverUMDF
呼叫WdfDeviceCreateDeviceInterface
。 將不正確的參數取代為 Trace.h 中定義的名稱,以確保驅動程式正確建置。
- 裝置介面 GUID 定義於 Trace.h 中,並從 Device.c 中參考
- 從 [建置] 功能表中,選取 [建置解決方案]。
如需詳細資訊,請參閱 建置驅動程式。
步驟 4:設定計算機以進行測試和偵錯
若要測試和偵錯驅動程式,您可以在主計算機上執行調試程式,並在目標計算機上執行驅動程式。 到目前為止,您已在主計算機上使用 Visual Studio 來建置驅動程式。 接下來,您必須設定目標計算機。 若要設定目標計算機,請遵循布建計算機以進行驅動程式部署和測試中的指示。
步驟 5:啟用核心偵錯的追蹤
範本程式代碼包含數個追蹤訊息(TraceEvents),可協助您追蹤函式呼叫。 原始碼中的所有函式都包含標記例程進入和結束的追蹤訊息。 針對錯誤,追蹤訊息包含錯誤碼和有意義的字串。 由於 WPP 追蹤已啟用驅動程式專案,因此在建置程式期間建立的 PDB 符號檔包含追蹤訊息格式設定指示。 如果您設定 WPP 追蹤的主電腦和目標電腦,驅動程式可以將追蹤訊息傳送至檔案或調試程式。
設定主計算機以進行WPP追蹤
從 PDB 符號檔擷取追蹤訊息格式指示,以建立追蹤訊息格式 (TMF) 檔案。
您可以使用Tracepdb.exe來建立TMF檔案。 此工具位於 WDK 的安裝資料夾>Windows Kits\10\bin\<architecture> 資料夾中。< 下列命令會建立驅動程序專案的TMF檔案。
tracepdb -f <PDBFiles> -p <TMFDirectory>
-f 選項會指定 PDB 符號檔的位置和名稱。 -p 選項會指定 Tracepdb 所建立之 TMF 檔案的位置。 如需詳細資訊,請參閱 Tracepdb 命令。
指定位置有三個檔案,每個 C 程式代碼檔案在專案中一個。 它們會提供 GUID 檔名。
在除錯程式中,輸入下列命令:
.load Wmitrace .chain !wmitrace.searchpath + <TMF file location>
這些命令:
- 載入Wmitrace.dll延伸模組。
- 確認調試程式延伸模組已載入。
- 將TMF檔案的位置新增至調試程式的搜尋路徑。
輸出看起來會像這樣:
Trace Format search path is: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE;c:\drivers\tmf
設定 WPP 追蹤的目標電腦
請確定您的目標電腦上有 Tracelog 工具。 此工具位於 WDK 的 install_folder>Windows Kits\10\Tools\<arch> 資料夾中。< 如需詳細資訊,請參閱 Tracelog 命令語法。
開啟命令 視窗 ,並以系統管理員身分執行。
輸入以下命令:
tracelog -start MyTrace -guid \#c918ee71-68c7-4140-8f7d-c907abbcb05d -flag 0xFFFF -level 7-rt -kd
此命令會啟動名為 MyTrace 的追蹤作業階段。
guid 自變數會指定追蹤提供者的 GUID,這是客戶端驅動程式。 您可以從 Visual Studio 2022 專案中的 Trace.h 取得 GUID。 另一個選項是,您可以輸入下列命令,並在 .guid 檔案中指定 GUID。 檔案包含連字元格式的 GUID:
tracelog -start MyTrace -guid c:\\drivers\\Provider.guid -flag 0xFFFF -level 7-rt -kd
您可以輸入下列命令來停止追蹤工作階段:
tracelog -stop MyTrace
步驟 6:在目標計算機上部署驅動程式
- 在 [方案總管] 視窗中,以滑鼠右鍵按兩下專案名稱 (MyUSBDriver_UMDF_),然後選擇 [屬性]。
- 在左窗格中,流覽至 [ 組態屬性 > 驅動程式安裝 > 部署]。
- 針對 [ 目標裝置名稱],指定目標計算機的名稱。
- 選取 [ 安裝/重新安裝] 和 [驗證]。
- 選取 [確定]。
- 在 [偵錯] 功能表上,選擇 [開始偵錯],或在鍵盤上按 F5。
注意
請勿在 [硬體標識符驅動程式更新] 底下指定裝置的硬體識別碼。 硬體識別碼必須只在驅動程式的資訊 (INF) 檔案中指定。
步驟 7:在 裝置管理員 中檢視驅動程式
輸入下列命令以開啟 裝置管理員。
devmgmt
確認 裝置管理員 顯示下列節點。
USB 裝置
MyUSBDriver_UMDF_Device
步驟 8:在調試程式中檢視輸出
確認追蹤訊息出現在 主電腦上的 [調試程序即時運算視窗 ] 中。
輸出應如下所示:
[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Entry
[0]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::OnPrepareHardware Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Entry
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::Initialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyIoQueue::CreateInstanceAndInitialize Exit
[1]0744.05F0::00/00/0000-00:00:00.000 [MyUSBDriver_UMDF_]CMyDevice::Configure Exit
備註
讓我們看看架構和客戶端驅動程式如何一起運作,以與 Windows 互動,並處理傳送至 USB 裝置的要求。 此圖顯示針對 UMDF 型 USB 用戶端驅動程式載入系統中的模組。
每個模組的用途如下所述:
- 應用程式 - 使用者模式程式,會發出與 USB 裝置通訊的 I/O 要求。
- I/O 管理員 - 建立 I/O 要求封包的 Windows 元件,代表已接收的應用程式要求,並將其轉送至目標裝置核心模式裝置堆疊的頂端。
- 反映器 - 安裝在內核模式裝置堆疊頂端Microsoft提供的核心模式驅動程式(WUDFRd.sys)。 反映器會將從 I/O 管理員收到的 IRP 重新導向至用戶端驅動程式主機進程。 收到要求時,架構和用戶端驅動程序會處理要求。
- 主機進程 - 使用者模式驅動程式執行的進程(Wudfhost.exe)。 它也裝載架構和 I/O 發送器。
- 用戶端驅動程式 - USB 裝置的使用者模式函式驅動程式。
- UMDF — 代表用戶端驅動程序處理與 Windows 大部分互動的架構模組。 它會公開客戶端驅動程式可用來執行一般驅動程式工作的使用者模式設備驅動器介面 (DIS)。
- 發送器— 在主機進程中執行的機制;決定如何在使用者模式驅動程序處理要求之後,將要求轉送至核心模式,並已到達使用者模式堆疊的底部。 在圖例中,發送器會將要求轉送至使用者模式 DLL,Winusb.dll。
- Winusb.dll - Microsoft提供的使用者模式 DLL,可公開 WinUSB Functions ,以簡化用戶端驅動程式與 WinUSB 之間的通訊程式(Winusb.sys,以核心模式載入)。
- Winusb.sys - 所有適用於 USB 裝置的 UMDF 用戶端驅動程式都需要Microsoft提供的驅動程式。 驅動程式必須安裝在反映器下方,並作為核心模式中USB驅動程式堆疊的閘道。 如需詳細資訊,請參閱 WinUSB for Developers 簡介。
- USB 驅動程式堆疊 — 一組驅動程式,由 Microsoft 提供,可處理與 USB 裝置的通訊協定層級通訊。 如需詳細資訊,請參閱 Windows 中的 USB 主機端驅動程式。
每當應用程式提出 USB 驅動程式堆疊的要求時,Windows I/O 管理員就會將要求傳送至反映器,以在使用者模式中將它導向至用戶端驅動程式。 用戶端驅動程式會藉由呼叫特定的 UMDF 方法來處理要求,此方法會在內部呼叫 WinUSB Functions ,以將要求傳送至 WinUSB。 收到要求后,WinUSB 會處理要求,或將它轉送至USB驅動程式堆疊。