與 USB 裝置交談,開始完成 (UWP 應用程式)
本文提供建立與 USB 裝置交談的 UWP 應用程式端對端逐步解說。
使用 Windows 執行階段 API 來撰寫 UWP 應用程式,讓使用者能夠存取其周邊 USB 裝置。 這類應用程式可以根據使用者指定的準則連線到裝置、取得裝置的相關信息、將數據傳送至裝置,並相反地從裝置取得數據流,以及輪詢裝置以取得中斷數據。
在這裡,我們將說明 UWP app 如何實作這些工作,並連結到示範如何使用 Windows.Devices.Usb 中包含的類別的範例。 我們將探討應用程式指令清單中所需的裝置功能,以及如何在裝置連線時啟動應用程式。 我們將示範如何在背景執行數據傳輸工作,即使應用程式暫停以節省電池使用時間。
逐步解說- 撰寫適用於 USB 裝置的 UWP 應用程式
請遵循本文中的步驟,或直接跳至 自定義 USB 裝置存取範例。 隨附範例會實作此處的所有步驟,但為了讓事情持續移動,我們不會逐步執行程序代碼。 某些步驟會在範例區段中找到它,以協助您快速尋找程序代碼。 範例原始程式檔的結構很簡單且一般,因此您可以輕鬆地尋找程序代碼,而不需要向下切入多個來源檔案層。 但您可能偏好以不同的方式分手並組織自己的專案。
安裝 Microsoft WinUSB 驅動程式
安裝Microsoft提供的 WinUSB 驅動程式作為裝置的功能驅動程式。
您可以透過下列方式安裝Winusb.sys:
- 當您連線裝置時,您可能會注意到 Windows 會自動載入Winusb.sys,因為裝置是 WinUSB 裝置。
- 在 裝置管理員 中指定系統提供的裝置類別,以安裝驅動程式。
- 使用自訂 INF 安裝驅動程式。 您可以透過下列兩種方式之一取得 INF:
- 從硬體廠商取得 INF。
- 撰寫參考Microsoft所提供 Winusb.inf 檔案的自定義 INF。 如需詳細資訊,請參閱 WinUSB (Winusb.sys) 安裝。
取得裝置的相關信息
取得裝置介面 GUID、硬體識別碼和裝置類別的相關信息。
您可以從裝置製造商取得該資訊。
廠商和產品標識碼
在 裝置管理員 中,檢視裝置屬性。 在 [ 詳細數據] 索引標籤上 ,檢視 [硬體標識符 ] 屬性值。 該值是這兩個標識碼的組合。 例如,針對 SuperMUTT 裝置, 硬體識別碼 為 「USB\VID_045E&PID_F001」;廠商標識碼為 「0x045E」,而產品標識碼為 「0xF001」。
裝置類別、子類別和通訊協議代碼
裝置介面 GUID
或者,您可以檢視登錄的資訊。 如需詳細資訊,請參閱 USB裝置登錄專案。
判斷 USB API 集合是否允許裝置類別、子類別和通訊協定
如果裝置類別、子類別和裝置的通訊協定程式代碼位於下列清單中,您可以撰寫 UWP 應用程式:
name:cdcControl, classId:02 * *
name:physical, classId:05 * *
name:personalHealthcare, classId:0f 00 00
name:activeSync, classId:ef 01 01
name:palmSync, classId:ef 01 02
name:deviceFirmwareUpdate, classId:fe 01 01
name:irda, classId:fe 02 00
name:measurement, classId:fe 03 *
name:vendorSpecific, classId:ff * *
建立基本 Visual Studio 專案
建立您可以在本教學課程中擴充的基本Visual Studio專案。
如需詳細資訊,請參閱 開始使用UWP應用程式。
將 USB 裝置功能新增至應用程式指令清單
瞭解如何將 USB 裝置功能新增至應用程式指令清單。
在文本編輯器中開啟 Package.appxmanifest 檔案,並將 Name 屬性設定為 “usb” 的 DeviceCapability 元素新增,如此範例所示。
注意
您無法在 Visual Studio 中修改 USB 裝置功能。 您必須以滑鼠右鍵按兩下 方案總管中的 Package.appxmanifest 檔案,然後選取 [開啟 With...],然後選取 [XML (Text) 編輯器]。 檔案會以純 XML 開啟。
<Capabilities>
<!--When the device's classId is FF * *, there is a predefined name for the class.
You can use the name instead of the class id.
There are also other predefined names that correspond to a classId.-->
<m2:DeviceCapability Name="usb">
<!--SuperMutt Device-->
<m2:Device Id="vidpid:045E 0611">
<!--<wb:Function Type="classId:ff * *"/>-->
<m2:Function Type="name:vendorSpecific"/>
</m2:Device>
</m2:DeviceCapability>
</Capabilities>
在範例 中尋找:USB 裝置功能位於 Package.appxmanifest 檔案中。
開啟裝置以進行通訊
擴充應用程式以開啟裝置以進行通訊。
- 藉由建置進階查詢語法 (AQS) 字串來尋找裝置,其中包含在列舉裝置集合中尋找裝置的搜尋準則。
- 以下列兩種方式之一開啟裝置:
將 AQS 傳遞至 FindAllAsync 並取得裝置的 DeviceInformation 物件。
如需詳細資訊,請參閱 快速入門:列舉常用的裝置。
使用 DeviceWatcher 物件來偵測何時從系統新增或移除裝置。
- 將 AQS 傳遞至 CreateWatcher 並取得 DeviceWatcher 物件。
- 在 DeviceWatcher 對象上註冊事件處理程式。
- 取得 [新增] 事件處理程序中裝置的 DeviceInformation 物件。
- 啟動和停止 DeviceWatcher 物件。
如需詳細資訊,請參閱 如何在新增、移除或變更裝置時取得通知。
- 從 DeviceInformation.Id 屬性取得裝置實例。
- 傳遞裝置實例字串並取得 UsbDevice 物件,以呼叫 FromIdAsync。
在範例中尋找: 請參閱名為 Scenario1_DeviceConnect 的檔案。
研究 USB 裝置配置
研究您的 USB裝置配置。
檢閱有關設定裝置和執行數據傳輸的基本 USB 概念: 所有 USB 開發人員的概念。
檢視裝置組態描述元、每個支援的替代設定介面描述元,以及其端點描述元。 藉由使用 USBView,您可以流覽所有 USB 控制器和與其連線的 USB 裝置,以及檢查裝置設定。
取得並顯示 UI 中的 USB 描述元
擴充應用程式,以取得並顯示UI中的USB描述元。
取得 UsbDevice.DeviceDescriptor 值,以取得 裝置描述元 。
取得 UsbConfiguration.ConfigurationDescriptor 值,以取得組 態描述元 。
- 取得 UsbConfiguration.Descriptors 屬性來設定完整的組態描述元。
取得UsbConfiguration.UsbInterfaces屬性,以取得組態內的介面陣列。
取得 UsbInterface.InterfaceSettings 以取得替代設定的陣列。
在作用中的替代設定中,列舉管道並取得相關聯的端點。
這些物件代表端點描述元:
在範例中尋找: 請參閱名為 Scenario5_UsbDescriptors 的檔案。
傳送廠商定義的USB控制傳輸
擴充應用程式以傳送廠商定義的USB控制傳輸。
快速入門:如何傳送 USB 控制項傳輸要求 (UWP app)
- 從裝置的硬體規格取得廠商命令。
- 建立 UsbSetupPacket 物件,並藉由設定各種屬性填入設定封包。
- 根據傳輸的方向,啟動異步操作以透過這些方法傳送控制傳送:
在範例中尋找: 請參閱名為 Scenario2_ControlTransfer 的檔案。
讀取或寫入大量數據
擴充應用程式以讀取或寫入大量數據。
快速入門:如何傳送 USB 大量傳輸要求 (UWP 應用程式)
- 取得大量管道物件 (UsbBulkOutPipe 或 UsbBulkInPipe)。
- 設定大量管道以設定原則參數。
- 使用 DataReader 或 DataWriter 物件設定數據流。
- 呼叫 DataReader.LoadAsync 或 DataWriter.StoreAsync 來啟動異步傳輸作業。
- 取得傳輸作業的結果。
在範例中尋找: 請參閱名為 Scenario4_BulkPipes 的檔案。
取得硬體中斷數據
擴充應用程式以取得硬體中斷數據。
快速入門:如何傳送 USB 中斷傳輸要求 (UWP app)
- 取得插斷管道物件 (UsbInterruptInPipe 或 UsbInterruptOutPipe)。
- 實作 DataReceived 事件的中斷處理程式。
- 註冊事件處理程式以開始接收數據。
- 取消註冊事件處理程式以停止接收數據。
在範例中尋找: 請參閱名為 Scenario3_InterruptPipes 的檔案。
選取目前未使用中的介面設定
擴充應用程式以選取目前未使用中的介面設定。
當裝置開啟進行通訊時,會選取預設介面及其第一個設定。 如果您想要變更該設定,請遵循下列步驟:
- 使用 UsbInterfaceSetting.Selected 值取得 USB 介面的作用中設定。
- 藉由呼叫 UsbInterfaceSetting.SelectSettingAsync 啟動異步操作來設定 USB 介面設定。
關閉裝置
擴充應用程式以關閉裝置。
使用 UsbDevice 物件之後,請關閉裝置。
C++應用程式必須使用 delete 關鍵詞來釋放參考。 C#/VB 應用程式必須呼叫 UsbDevice.Dispose 方法。 JavaScript 應用程式必須呼叫 UsbDevice.Close。
在範例中尋找: 請參閱名為 Scenario1_DeviceConnect 的檔案。
建立裝置元數據套件
建立應用程式的裝置元數據套件。
工具:裝置元數據撰寫精靈
- 如果您已安裝 Windows 驅動程式套件 (WDK),請開啟 [驅動程式>裝置元數據>撰寫]。
- 如果您已安裝獨立 SDK,此工具位於 <install_path>\bin\x86\DeviceMetadataWizardexe。
遵循精靈中的步驟,將您的應用程式與裝置產生關聯。 輸入有關您的裝置的這項資訊:
- 在 [ 裝置資訊] 頁面上,輸入 型號名稱、 製造商和 描述。
- 在 [ 硬體資訊] 頁面上,輸入裝置的硬體標識符。
若要將應用程式宣告為裝置的特殊許可權應用程式,請遵循下列指示:
在 [應用程式資訊] 頁面的 [特殊許可權] 應用程式群組中,輸入套件名稱、發行者名稱和 UWP 應用程式識別碼。
注意
請勿檢查 Access 自定義驅動程式 選項。
開啟 [完成] 索引標籤。選取 [將套件複製到您系統的本機元數據存放區] 複選框。
在 控制台 中連線裝置,開啟 [檢視裝置和印表機],並確認裝置的圖示正確無誤。
在範例中尋找它: 請參閱 DeviceMetadata 資料夾。
實作自動播放啟用
藉由實作自動播放啟用來擴充應用程式,以在裝置連線到系統時啟動應用程式。
快速入門:註冊自動播放裝置的應用程式
您可以新增自動播放功能,讓應用程式在裝置連線到系統時啟動。 您可以啟用所有 UWP app 的自動播放功能(特殊許可權或其他)。
在您的裝置元資料套件中,您必須指定裝置應如何響應自動播放通知。 在 [ Windows 資訊] 索引標籤上 ,選取 [UWP 裝置應用程式 ] 選項並輸入應用程式資訊,如下所示:
在應用程式指令清單中,新增 自動播放裝置 宣告和啟動資訊,如下所示:
在 App 類別的 OnActivated 方法中,檢查裝置是否已啟動應用程式。 如果是,則方法會接收包含 DeviceInformation.Id 屬性值的 DeviceEventArgs 參數值。 這是開啟裝置以進行通訊中所述的相同值。
在範例中尋找它: 請參閱名為 Autoplay 的檔案。 如需 JavaScript,請參閱default.js。
實作背景工作
擴充應用程式以實作背景工作,以執行傳送到裝置的長度,例如韌體更新,而不需要暫停應用程式。
若要實作背景工作,您需要兩個類別。
背景工作類別會實作 IBackgroundTask 介面,並包含您建立以同步處理或更新周邊裝置的實際程序代碼。 背景工作類別會在背景工作觸發應用程式指令清單中提供的進入點時執行。
注意
Windows 8.1 所提供的裝置背景工作基礎結構。 如需 Windows 背景工作的詳細資訊,請參閱 使用背景工作支援您的應用程式。
背景工作類別
- 實作 Windows 背景工作基礎結構所需的 IBackgroundTask 介面。
- 取得 Run 方法中傳遞至 類別的 DeviceUseDetails 實例,並使用這個實例向 Microsoft Store 應用程式回報進度,並註冊取消事件。
- Run 方法也會呼叫實作背景裝置同步程式代碼的私人 OpenDevice 和 WriteToDeviceAsync 方法。
UWP 應用程式會註冊並觸發 DeviceUseTrigger 背景工作。 應用程式會在背景工作上註冊、觸發及處理進度。
注意
下列範例程式代碼可以使用對應的物件,套用至 DeviceServicingTrigger 背景工作。 兩個觸發程式物件與其對應 API 之間的唯一差異是 Windows 所做的原則檢查。
- 建立 DeviceUseTrigger 和 BackgroundTaskRegistration 物件。
- 檢查此範例應用程式先前是否已註冊任何背景工作,並藉由在工作上呼叫 Unregister 方法來取消這些工作。
- 註冊與裝置同步的背景工作。 下一個步驟中的 SyncWithDeviceAsync 方法會呼叫 SetupBackgroundTask 方法。
- 初始化 DeviceUseTrigger,並儲存以供稍後使用。
- 建立 BackgroundTaskBuilder 物件,並使用其 Name、TaskEntryPoint 和 SetTrigger 屬性和方法來註冊應用程式的 DeviceUseTrigger 物件和背景工作名稱。 BackgroundTaskBuilder 物件的 TaskEntryPoint 屬性會設定為觸發背景工作時所要執行之背景工作類別的完整名稱。
- 從背景工作註冊完成和進度事件,讓Microsoft市集應用程式可以提供完成和進度更新給使用者。
- 私人 SyncWithDeviceAsync 方法會註冊與裝置同步的背景工作,並啟動背景同步處理。
從上一個步驟呼叫 SetupBackgroundTask 方法,並註冊將與裝置同步的背景工作。
呼叫啟動背景工作的私人 StartSyncBackgroundTaskAsync 方法。
關閉應用程式的裝置句柄,以確保背景工作能夠在裝置啟動時開啟裝置。
注意
背景工作必須開啟裝置以執行更新,因此Microsoft市集應用程式必須在呼叫 RequestAsync 之前關閉裝置的連線
呼叫 DeviceUseTrigger 物件的 RequestAsync 方法,此方法會啟動觸發背景工作,並從 RequestAsync 傳回 DeviceTriggerResults 物件,以判斷背景工作是否成功啟動。
注意
Windows 檢查,以確保所有必要的工作初始原則檢查都已完成。 如果完成所有原則檢查,更新作業現在會以Microsoft市集應用程式以外的背景工作的形式執行,讓應用程式在作業進行時安全地暫停。 如果不再符合這些需求,Windows 也會強制執行任何運行時間需求,並取消背景工作。
使用從 StartSyncBackgroundTaskAsync 傳回的 DeviceTriggerResults 對象來判斷背景工作是否成功啟動。 switch 語句可用來檢查 DeviceTriggerResults 的結果。
- 實作私人 OnSyncWithDeviceProgress 事件處理程式,以從背景工作進度更新應用程式 UI。
- 實作私人 OnSyncWithDeviceCompleted 事件處理程式,以在背景工作完成時處理從背景工作轉換到前景應用程式的轉換。
- 使用 BackgroundTaskCompletedEventArgs 物件的 CheckResults 方法,判斷背景工作是否擲回任何例外狀況。
- 應用程式會重新開啟裝置以供前景應用程式使用,現在背景工作已完成,並更新UI以通知使用者。
- 從UI實作私用按鈕按下事件處理程式,以啟動和取消背景工作。
- 私用Sync_Click事件處理程式會呼叫先前步驟中所述的 SyncWithDeviceAsync 方法。
- 私用CancelSync_Click事件處理程式會呼叫 private CancelSyncWithDevice 方法來取消背景工作。
- 私用 CancelSyncWithDevice 方法會取消註冊並取消任何作用中的裝置同步處理,以便使用 BackgroundTaskRegistration 物件上的 Unregister 方法重新開啟裝置。
在範例中尋找: 請參閱名為 Scenario7_Sync 檔案的檔案。 背景類別是在IoSyncBackgroundTask中實作。
執行 Windows 應用程式認證套件
執行 Windows 應用程式認證套件。
建議。 執行 Windows 應用程式認證套件可協助您確定您的應用程式符合Microsoft市集需求。 每當您將主要功能新增至應用程式時,您應該執行它。
相關範例
深入瞭解如何設計 UWP 應用程式 UI。
使用 C# 和 Visual Basic 的 UWP app 藍圖,以及 使用 C++ 的 UWP app 藍圖
深入瞭解如何使用 C++、C# 或 Visual Basic 建立 UWP 應用程式。
瞭解如何讓您的 app 在進行可能需要較長時間的工作時保持回應。