WinUSB テンプレートに基づいて Windows デスクトップ アプリを記述する

USB デバイスと通信する Windows デスクトップ アプリを記述する最も簡単な方法は、C/C++ WinUSB テンプレートを使用することです。 このテンプレートには、Windows Driver Kit (WDK) (Windows 用デバッグ ツールを使用) と Microsoft Visual Studio (Professional または Ultimate) を統合した環境が必要です。 このテンプレートを出発点として使用できます。

開始する前に

  • 統合開発環境を設定するには、まず Microsoft Visual Studio Ultimate 2019 または Microsoft Visual Studio Professional 2019 をインストールしてから、WDK をインストールします。 Visual Studio と WDK のセットアップ方法に関する情報は、WDK ダウンロード ページをご覧ください。
  • Windows 用デバッグ ツールは、WDK をインストールするときに組み込まれます。 詳細については、「Windows 用デバッグ ツールのダウンロードとインストール」を参照してください。

WinUSB アプリケーションの作成

テンプレートからアプリケーションを作成するには:

  1. [新しいプロジェクト] ダイアログ ボックスの上部にある検索ボックスに、もう一度「USB」と入力します。

  2. 中央のウィンドウで、[WinUSB アプリケーション (ユニバーサル)] を選択します。

  3. [次へ] を選択します。

  4. プロジェクト名を入力し、保存場所を選択して、[作成] を選択します。

    次のスクリーンショットは、WinUSB アプリケーション (ユニバーサル) テンプレートの [新しいプロジェクト] ダイアログ ボックスを示しています。

    winusb template new project creation first screen.

    winusb template new project creation second screen.

    このトピックでは、Visual Studio プロジェクトの名前が USB Application1 であることを前提としています。

    Visual Studio により、1 つのプロジェクトと 1 つのソリューションが作成されます。 次のスクリーン ショットに示すように、ソリューション、プロジェクト、およびプロジェクトに属するファイルは、[ソリューション エクスプローラー] ウィンドウで確認できます。 ([ソリューション エクスプローラー] ウィンドウが表示されない場合は、[表示] メニューから [ソリューション エクスプローラー] を選択します)。このソリューションには、USB Application1 という名前の C++ アプリケーション プロジェクトが含まれています。

    winusb template solution explorer 1.

    USB Application1 プロジェクトには、アプリケーションのソース ファイルがあります。 アプリケーションのソース コードを確認する場合は、[ソース ファイル] の下に表示されるすべてのファイルを開くことができます。

  5. ソリューションにドライバー パッケージ プロジェクトを追加します。 ソリューション (ソリューション 'USB Application1') を長押し (または右クリック) し、次のスクリーンショットに示すように [追加>新しいプロジェクト] を選択します。

    winusb template creation second project addition.

  6. [新しいプロジェクト] ダイアログ ボックスの上部にある検索ボックスに、もう一度「USB」と入力します。

  7. 中央のウィンドウで、[WinUSB INF ドライバー パッケージ] を選択します。

  8. [次へ] を選択します。

  9. プロジェクト名を入力して、[作成] を選択します。

    次のスクリーンショットは、WinUSB INF ドライバー パッケージ テンプレートの [新しいプロジェクト] ダイアログ ボックスを示しています。

    winusb template second project creation first screen.

    winusb template second project creation second screen.

    このトピックでは、Visual Studio プロジェクトの名前が USB Application1 Package であることを前提としています。

    USB Application1 Package プロジェクトには、デバイス ドライバーとしてマイクロソフト提供の Winusb.sys ドライバーをインストールするために使用される INF ファイルが含まれています。

    次のスクリーンショットに示すように、ソリューション エクスプローラーには両方のプロジェクトが含まれているはずです。

    winusb template solution explorer 2.

  10. INF ファイル USBApplication1.inf で、次のコードを見つけます: %DeviceName% =USB_Install, USB\VID_vvvv&PID_pppp

  11. VID_vvvv&PID_pppp をデバイスのハードウェア ID に置き換えます。 デバイス マネージャーからハードウェア ID を取得します。 デバイス マネージャーで、デバイスのプロパティを表示します。 [詳細] タブで、[ハードウェアID] プロパティの値を表示します。

  12. [ソリューション エクスプローラー] ウィンドウで、ソリューション 'USB Application1' (2 つのプロジェクトのうち 2 つ) を選択して長押し (または右クリック) して、[構成マネージャー] を選択します。 アプリケーション プロジェクトとパッケージ プロジェクトの両方の構成とプラットフォームを選択します。 この演習では、次のスクリーン ショットに示すように、[デバッグ] と [x64] を選択します。

Screenshot that shows the

プロジェクトのビルド、デプロイ、デバッグ

この演習ではこれまで、Visual Studio を使用してプロジェクトを作成しました。 次に、デバイスが接続されているデバイスを構成する必要があります。 このテンプレートでは、Winusb ドライバーがデバイスのドライバーとしてインストールされている必要があります。

テスト環境とデバッグ環境には、次の機能があります。

  • 2 台のコンピューターセットアップ: ホスト コンピューターとターゲット コンピューター。 ホスト コンピューター上の Visual Studio でプロジェクトを開発し、ビルドします。 デバッガーはホストコンピュータ上で実行され、Visual Studio のユーザーインターフェイスで使用できます。 アプリケーションをテストしてデバッグすると、ドライバーはターゲットコンピュータ上で実行されます。

  • 単一コンピューターのセットアップ: ターゲットとホストは 1 台のコンピューターで実行されます。 Visual Studio でプロジェクトを開発してビルドし、デバッガーとアプリケーションを実行します。

次の手順に従って、アプリケーションとドライバーをデプロイ、インストール、読み込み、デバッグできます。

  • 2 台のコンピューターのセットアップ

    1. ドライバーのデプロイとテスト用にコンピューターをプロビジョニングする」の手順に従って、ターゲット コンピューターをプロビジョニングします。 注: プロビジョニングにより、WDKRemoteUser という名前のターゲット コンピューターにユーザーが作成されます。 プロビジョニングが完了すると、ユーザーが WDKRemoteUser に切り替わります。
    2. ホスト コンピューターで、Visual Studio でソリューションを開きます。
    3. main.cpp で、OpenDevice 呼び出しの前にこの行を追加します。
    system ("pause")
    

    この行を使用すると、起動時にアプリケーションが一時停止します。 これはリモート デバッグで役立ちます。

    1. pch.h には、次の行を含めます。
    #include <cstdlib>
    

    前の手順の system() 呼び出しには、この include ステートメントが必要です。

    1. [ソリューション エクスプローラー] ウィンドウで、[USB Application1 Package] を選択して長押し (または右クリック) して、[プロパティ] を選択します。

    2. 次のスクリーン ショットに示すように、[USB Application1 Package プロパティ ページ] ウィンドウの左側のウィンドウで、[構成プロパティ>ドライバーのインストール>デプロイ] に移動します。

    3. デプロイ前に以前のドライバーバージョンを削除にチェックを入れます。

    4. [リモート コンピューター名] で、テストとデバッグ用に構成したコンピューターの名前を選択します。 この演習では、dbg-target という名前のコンピューターを使用します。

    5. [インストール/再インストールと確認] を選択します。 適用を選択します。

      winusb template deployment.

    6. プロパティ ページで、[構成プロパティ > デバッグ] に移動し、次のスクリーン ショットに示すように、[Windows のデバッグ ツール – リモート デバッガー] を選択します。

      winusb template remote debugger.

    7. [ビルド] メニューの [ソリューションのビルド] をクリックします。 Visual Studio では、出力ウィンドウにビルドの進捗状況が表示されます。 ([出力] ウィンドウが表示されない場合は、[表示] メニューから [出力] を選択します)。この演習では、Windows 10 を実行する x64 システム用のプロジェクトをビルドしました。

    8. [ビルド] メニューの [ソリューションの配置] を選択します。

ターゲット コンピューターでは、ドライバーのインストール スクリプトが実行されていることがわかります。 ドライバー ファイルは、ターゲット コンピューターの %Systemdrive%\drivertest\drivers フォルダーにコピーされます。 .inf、.cat、test cert、.sys など、必要なファイルがすべて %systemdrive%\drivertest\drivers フォルダーに存在することを確認します。 デバイスは、エラーなしでデバイス マネージャーに表示される必要があります。

ホスト コンピューターの [出力] ウィンドウにこのメッセージが表示されます。

Deploying driver files for project
"<path>\visual studio 14\Projects\USB Application1\USB Application1 Package\USB Application1 Package.vcxproj".
Deployment may take a few minutes...
========== Build: 1 succeeded, 0 failed, 1 up-to-date, 0 skipped ==========

アプリケーションをデバッグするには

  1. ホスト コンピューターで、ソリューション フォルダー内の [x64 > Win8.1Debug] に移動します。

  2. ターゲット コンピューターに、UsbApplication1.exe アプリケーションの実行可能ファイルをコピーします。

  3. ターゲット コンピューターでアプリケーションを起動します。

  4. ホスト コンピューターで、[デバッグ] メニューの [プロセスにアタッチする] を選択します。

  5. このウィンドウで、トランスポートとして Windows ユーザー モード デバッガー (Windows 用デバッグ ツール) を選択し、ターゲット コンピューターの名前 (この場合は dbg-target) を、この図に示すように修飾子として選択します。

    winusb template debug setting.

  6. そのプロセスを [選択可能なプロセス] の一覧から選択し、[アタッチ] を選択します。 [イミディエイト ウィンドウ] を使用するか、[デバッグ] メニューのオプションを使用してデバッグできるようになりました。

前の手順では、Windows 用のデバッグ ツール – リモート デバッガーを使用してアプリケーションをデバッグします。 リモート Windows デバッガー (Visual Studio に含まれるデバッガー) を使用する場合は、次の手順に従います。

  1. ターゲット コンピューターで、ファイアウォールで許可されているアプリの一覧に msvsmon.exe を追加します。
  2. C:\DriverTest\msvsmon\msvsmon.exe にある Visual Studio リモート デバッグ モニターを起動します。
  3. C:\remotetemp のような作業フォルダーを作成します。
  4. ターゲット コンピューター上の作業フォルダーに UsbApplication1.exe アプリケーションの実行可能ファイルをコピーします。
  5. ホスト コンピューターの Visual Studio で、USB Application1 Package プロジェクトを右クリックし、[プロジェクトのアンロード] を選択します。
  6. USB Application1 プロジェクトを長押し (または右クリック) して、プロジェクトのプロパティで [構成プロパティ] ノードを展開し、[デバッグ] を選択します。
  7. [起動するデバッガー][リモート Windows デバッガー] に変更します。
  8. ローカルでビルドされたプロジェクトのリモート デバッグ」の手順に従って、リモート コンピューターで実行可能ファイルを実行するようにプロジェクト設定を変更します。 作業ディレクトリリモート コマンドのプロパティに、ターゲット コンピューター上のフォルダーが反映されていることを確認します。
  9. アプリケーションをデバッグするには、[ビルド] メニューから [デバッグの開始] を選択するか、F5 キーを押します。
  • 1 台のコンピューターのセットアップ:

    1. アプリケーションとドライバー インストール パッケージをビルドするには、[ビルド] メニューの [ソリューションのビルド] を選択します。 Visual Studio では、出力ウィンドウにビルドの進捗状況が表示されます。 ([出力] ウィンドウが表示されない場合は、[表示] メニューから [出力] を選択します)。この演習では、Windows 10 を実行する x64 システム用のプロジェクトをビルドしました。

    2. ビルドされたドライバー パッケージを表示するには、Windows エクスプローラーで USB Application1 フォルダーに移動し、[x64] > [Debug] > [USB Application1 Package] に移動します。 ドライバー パッケージにはいくつかのファイルが含まれています。MyDriver.inf はドライバーのインストール時に Windows が使用する情報ファイルで、mydriver.cat はインストーラーがドライバー パッケージのテスト署名を検証するために使用するカタログ ファイルです。 これらのファイルを次のスクリーンショットに示します。

      winusb application template.

      パッケージに含まれるドライバー ファイルはありません。 これは、INF ファイルが Windows\System32 フォルダーにあるインボックス ドライバー Winusb.sys を参照しているためです。

    3. ドライバーを手動でインストールします。 [デバイス マネージャー] で、パッケージ内の INF を指定してドライバーを更新します。 前のセクションに示すように、[ソリューション] フォルダーにあるドライバー パッケージをポイントします。 エラー DriverVer set to a date in the future が表示された場合は、[INF パッケージ プロジェクト設定] > [Inf2Cat] > [全般] > [現地時刻の使用] > [はい] を設定します。

    4. USB Application1 プロジェクトを長押し (または右クリック) して、プロジェクトのプロパティで [構成プロパティ] ノードを展開し、[デバッグ] を選択します。

    5. [起動するデバッガー][ローカル Windows デバッガー] に変更します。

    6. USB Application1 Package プロジェクトを長押し (または右クリック) して、[プロジェクトのアンロード] を選択します。

    7. アプリケーションをデバッグするには、[ビルド] メニューから [デバッグの開始] を選択するか、F5 キーを押します。

テンプレート コードの説明

テンプレートは、デスクトップ アプリケーションの開始点です。 USB Application1 プロジェクトには、ソース ファイル device.cpp と main.cpp があります。

main.cpp ファイルには、アプリケーションのエントリ ポイント、_tmain が含まれています。 device.cpp には、デバイスのハンドルを開いたり閉じたりするすべてのヘルパー関数が含まれています。

テンプレートには、device.h という名前のヘッダー ファイルもあります。 このファイルには、デバイス インターフェイス GUID (後述) と、アプリケーションによって取得された情報を格納する DEVICE_DATA 構造体の定義が含まれています。 たとえば、OpenDevice によって取得され、後続の操作で使用される WinUSB インターフェイス ハンドルを格納します。

typedef struct _DEVICE_DATA {

    BOOL                    HandlesOpen;
    WINUSB_INTERFACE_HANDLE WinusbHandle;
    HANDLE                  DeviceHandle;
    TCHAR                   DevicePath[MAX_PATH];

} DEVICE_DATA, *PDEVICE_DATA;

デバイスのインスタンス パスの取得 - device.cpp の RetrieveDevicePath を参照してください

USB デバイスにアクセスするために、アプリケーションは CreateFile を呼び出してデバイスの有効なファイル ハンドルを作成します。 その呼び出しでは、アプリケーションはデバイス パス インスタンスを取得する必要があります。 デバイス パスを取得するために、アプリは SetupAPI ルーチンを使用し、Winusb.sysのインストールに使用された INF ファイル内のデバイス インターフェイス GUID を指定します。 Device.h は、GUID_DEVINTERFACE_USBApplication1 という名前の GUID 定数を宣言します。 これらのルーチンを使用して、アプリケーションは、指定されたデバイス インターフェイス クラス内のすべてのデバイスを列挙して、デバイスのデバイス パスを取得します。

HRESULT
RetrieveDevicePath(
    _Out_bytecap_(BufLen) LPTSTR DevicePath,
    _In_                  ULONG  BufLen,
    _Out_opt_             PBOOL  FailureDeviceNotFound
    )
/*++

Routine description:

    Retrieve the device path that can be used to open the WinUSB-based device.

    If multiple devices have the same device interface GUID, there is no
    guarantee of which one will be returned.

Arguments:

    DevicePath - On successful return, the path of the device (use with CreateFile).

    BufLen - The size of DevicePath's buffer, in bytes

    FailureDeviceNotFound - TRUE when failure is returned due to no devices
        found with the correct device interface (device not connected, driver
        not installed, or device is disabled in Device Manager); FALSE
        otherwise.

Return value:

    HRESULT

--*/
{
    BOOL                             bResult = FALSE;
    HDEVINFO                         deviceInfo;
    SP_DEVICE_INTERFACE_DATA         interfaceData;
    PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
    ULONG                            length;
    ULONG                            requiredLength=0;
    HRESULT                          hr;

    if (NULL != FailureDeviceNotFound) {

        *FailureDeviceNotFound = FALSE;
    }

    //
    // Enumerate all devices exposing the interface
    //
    deviceInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USBApplication1,
                                     NULL,
                                     NULL,
                                     DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

    if (deviceInfo == INVALID_HANDLE_VALUE) {

        hr = HRESULT_FROM_WIN32(GetLastError());
        return hr;
    }

    interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    //
    // Get the first interface (index 0) in the result set
    //
    bResult = SetupDiEnumDeviceInterfaces(deviceInfo,
                                          NULL,
                                          &GUID_DEVINTERFACE_USBApplication1,
                                          0,
                                          &interfaceData);

    if (FALSE == bResult) {

        //
        // We would see this error if no devices were found
        //
        if (ERROR_NO_MORE_ITEMS == GetLastError() &&
            NULL != FailureDeviceNotFound) {

            *FailureDeviceNotFound = TRUE;
        }

        hr = HRESULT_FROM_WIN32(GetLastError());
        SetupDiDestroyDeviceInfoList(deviceInfo);
        return hr;
    }

    //
    // Get the size of the path string
    // We expect to get a failure with insufficient buffer
    //
    bResult = SetupDiGetDeviceInterfaceDetail(deviceInfo,
                                              &interfaceData,
                                              NULL,
                                              0,
                                              &requiredLength,
                                              NULL);

    if (FALSE == bResult && ERROR_INSUFFICIENT_BUFFER != GetLastError()) {

        hr = HRESULT_FROM_WIN32(GetLastError());
        SetupDiDestroyDeviceInfoList(deviceInfo);
        return hr;
    }

    //
    // Allocate temporary space for SetupDi structure
    //
    detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)
        LocalAlloc(LMEM_FIXED, requiredLength);

    if (NULL == detailData)
    {
        hr = E_OUTOFMEMORY;
        SetupDiDestroyDeviceInfoList(deviceInfo);
        return hr;
    }

    detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    length = requiredLength;

    //
    // Get the interface's path string
    //
    bResult = SetupDiGetDeviceInterfaceDetail(deviceInfo,
                                              &interfaceData,
                                              detailData,
                                              length,
                                              &requiredLength,
                                              NULL);

    if(FALSE == bResult)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        LocalFree(detailData);
        SetupDiDestroyDeviceInfoList(deviceInfo);
        return hr;
    }

    //
    // Give path to the caller. SetupDiGetDeviceInterfaceDetail ensured
    // DevicePath is NULL-terminated.
    //
    hr = StringCbCopy(DevicePath,
                      BufLen,
                      detailData->DevicePath);

    LocalFree(detailData);
    SetupDiDestroyDeviceInfoList(deviceInfo);

    return hr;
}

前の関数では、アプリケーションは次のルーチンを呼び出してデバイス パスを取得します。

  1. デバイス情報セットへのハンドルを取得する SetupDiGetClassDevs 。指定されたデバイス インターフェイス クラスに一致するすべてのインストール済みデバイスに関する情報を含む配列、GUID_DEVINTERFACE_USBApplication1。 デバイス インターフェイスと呼ばれる配列内の各要素は、システムにインストールおよび登録されているデバイスに対応します。 デバイス インターフェイス クラスは、INF ファイルで定義したデバイス インターフェイス GUID を渡すことによって識別されます。 この関数は、HDEVINFO ハンドルをデバイス情報セットに返します。

  2. SetupDiEnumDeviceInterfaces を使用して、デバイス情報セット内のデバイス インターフェイスを列挙し、デバイス インターフェイスに関する情報を取得します。

    この呼び出しには、次のアイテムが必要です。

    • 初期化された呼び出し元によって割り当てられた SP_DEVICE_INTERFACE_DATA 構造体。cbSize メンバーが構造体のサイズに設定されています。

    • 手順 1 の HDEVINFO ハンドル。

    • INF ファイルで定義したデバイス インターフェイス GUID。

      SetupDiEnumDeviceInterfaces は、デバイス インターフェイスの指定したインデックスのデバイス情報セット配列を検索し、初期化された SP_DEVICE_INTERFACE_DATA 構造体にインターフェイスに関する基本的なデータを入力します。

    デバイス情報セット内のすべてのデバイス インターフェイスを列挙するには、関数が FALSE を返し、そのエラーのエラー コードが ERROR_NO_MORE_ITEMS になるまで、ループで SetupDiEnumDeviceInterfaces を呼び出ます。 ERROR_NO_MORE_ITEMS エラー コードは、GetLastError を呼び出すことによって取得できます。 反復処理のたびに、メンバー インデックスをインクリメントします。

    または、SetupDiEnumDeviceInfo を呼び出して、デバイス情報セットを列挙し、呼び出し元によって割り当てられた SP_DEVINFO_DATA 構造体で、インデックスで指定されたデバイス インターフェイス要素に関する情報を返すことができます。 その後、SetupDiEnumDeviceInterfaces 関数の DeviceInfoData パラメーターで、この構造体への参照を渡すことができます。

  3. デバイス インターフェイスの詳細なデータを取得するための SetupDiGetDeviceInterfaceDetail 。 情報は、SP_DEVICE_INTERFACE_DETAIL_DATA 構造体で返されます。 SP_DEVICE_INTERFACE_DETAIL_DATA 構造体のサイズは異なるため、SetupDiGetDeviceInterfaceDetail は 2 回呼び出されます。 最初の呼び出しでは、SP_DEVICE_INTERFACE_DETAIL_DATA 構造体に割り当てるバッファー サイズを取得します。 2 番目の呼び出しでは、割り当てられたバッファーにインターフェイスに関する詳細情報が入力されます。

    1. DeviceInterfaceDetailData パラメーターを NULL に設定して SetupDiGetDeviceInterfaceDetail を呼び出します。 この関数は、requiredlength パラメーターで正しいバッファー サイズを返します。 この呼び出しは、ERROR_INSUFFICIENT_BUFFER エラー コードで失敗します。 このエラー コードが発生します。
    2. requiredlength パラメーターで取得された適切なバッファー サイズに基づいて、SP_DEVICE_INTERFACE_DETAIL_DATA 構造体にメモリを割り当てます。
    3. SetupDiGetDeviceInterfaceDetail をもう一度呼び出し、DeviceInterfaceDetailData パラメーターで初期化された構造体への参照を渡します。 関数が戻ると、構造体にはインターフェイスに関する詳細情報が入力されます。 デバイス パスは、SP_DEVICE_INTERFACE_DETAIL_DATA 構造体の DevicePath メンバーにあります。

デバイスのファイル ハンドルの作成

device.cpp の OpenDevice を参照してください。

デバイスと対話するには、デバイス上の最初の (既定の) インターフェイスへの WinUSB インターフェイス ハンドルが必要です。 テンプレート コードは、ファイル ハンドルと WinUSB インターフェイス ハンドルを取得して、DEVICE_DATA 構造体に格納します。

HRESULT
OpenDevice(
    _Out_     PDEVICE_DATA DeviceData,
    _Out_opt_ PBOOL        FailureDeviceNotFound
    )
/*++

Routine description:

    Open all needed handles to interact with the device.

    If the device has multiple USB interfaces, this function grants access to
    only the first interface.

    If multiple devices have the same device interface GUID, there is no
    guarantee of which one will be returned.

Arguments:

    DeviceData - Struct filled in by this function. The caller should use the
        WinusbHandle to interact with the device, and must pass the struct to
        CloseDevice when finished.

    FailureDeviceNotFound - TRUE when failure is returned due to no devices
        found with the correct device interface (device not connected, driver
        not installed, or device is disabled in Device Manager); FALSE
        otherwise.

Return value:

    HRESULT

--*/
{
    HRESULT hr = S_OK;
    BOOL    bResult;

    DeviceData->HandlesOpen = FALSE;

    hr = RetrieveDevicePath(DeviceData->DevicePath,
                            sizeof(DeviceData->DevicePath),
                            FailureDeviceNotFound);

    if (FAILED(hr)) {

        return hr;
    }

    DeviceData->DeviceHandle = CreateFile(DeviceData->DevicePath,
                                          GENERIC_WRITE | GENERIC_READ,
                                          FILE_SHARE_WRITE | FILE_SHARE_READ,
                                          NULL,
                                          OPEN_EXISTING,
                                          FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
                                          NULL);

    if (INVALID_HANDLE_VALUE == DeviceData->DeviceHandle) {

        hr = HRESULT_FROM_WIN32(GetLastError());
        return hr;
    }

    bResult = WinUsb_Initialize(DeviceData->DeviceHandle,
                                &DeviceData->WinusbHandle);

    if (FALSE == bResult) {

        hr = HRESULT_FROM_WIN32(GetLastError());
        CloseHandle(DeviceData->DeviceHandle);
        return hr;
    }

    DeviceData->HandlesOpen = TRUE;
    return hr;
}
  1. アプリは CreateFile を呼び出し、前に取得したデバイス パスを指定してデバイスのファイル ハンドルを作成します。 WinUSB はこの設定に依存するため、FILE_FLAG_OVERLAPPED フラグを使用します。
  2. デバイスのファイル ハンドルを使用して、アプリは WinUSB インターフェイス ハンドルを作成します。 WinUSB 関数では、このハンドルを使用して、ファイル ハンドルではなくターゲット デバイスを識別します。 WinUSB インターフェイス ハンドルを取得するために、アプリはファイル ハンドルを渡すことによって WinUsb_Initialize を呼び出します。 後続の呼び出しで受信したハンドルを使用して、デバイスから情報を取得し、I/O 要求をデバイスに送信します。

デバイス ハンドルを解放する - device.cpp の CloseDevice を参照してください

テンプレート コードは、デバイスのファイル ハンドルと WinUSB インターフェイス ハンドルを解放するコードを実装します。

VOID
CloseDevice(
    _Inout_ PDEVICE_DATA DeviceData
    )
/*++

Routine description:

    Perform required cleanup when the device is no longer needed.

    If OpenDevice failed, do nothing.

Arguments:

    DeviceData - Struct filled in by OpenDevice

Return value:

    None

--*/
{
    if (FALSE == DeviceData->HandlesOpen) {

        //
        // Called on an uninitialized DeviceData
        //
        return;
    }

    WinUsb_Free(DeviceData->WinusbHandle);
    CloseHandle(DeviceData->DeviceHandle);
    DeviceData->HandlesOpen = FALSE;

    return;
}

次のステップ

次に、次のトピックを参照して、デバイス情報の取得とデバイスへのデータ転送の送信を行います。