none
USBドライブのVID/PIDを調べる方法について RRS feed

  • 質問

  • お世話になります。

    環境は、VS2005 C++で Win32アプリケーションで行っています。

    USBマスストレージを接続したドライブに対して、VendorIDと ProductIDを取得したいのですが、
    どのようにすれば良いでしょうか?

    行いたいのは、WM_DEVICECHANGE でデバイスの接続を感知し、
    接続されたドライブ(E: や F:)に対して、VID/PIDを取得したいのです。
    漠然とした質問で済みません。

    DDKの USBViewを見てみましたが、起動時にデバイス全てを列挙しており、
    表示されている USB情報にはドライブ情報がありませんでした。
    2010年2月4日 9:46

回答

  • 既に解決されているかもしれませんが。。。。

    私も以前に同じことを考えて、実際に出来ました。
    参考にしたのは、TDM850 4TXさんと同じく、WDK に同梱されている USBView です。

    使用する API は、Win32 API, Setup API, Configuration API と多岐にわたり、かなり面倒でした。
    一番の問題は、Drive Letter と、それに対応する USB Storage Device の関連をどのように取得するか、という点でした。

    Drive Letter はあくまでも User Mode 側の概念的な話なので、USBStor などの USB デバイス ドライバ側は、
    その USB Storage Device に割り当てられた Drive Letter を関知していません。
    なので、独自にその関係を割り出す処理が必要となります。

    私のとった実装の概要は、以下の通りです。

    1.  GetLogicalDriveString() / QueryDosDevice() / GetVolumeNameForVolumeMountPoint() API を組み合わせ、
         現在割り当てられている Drive Letter に対応する Volume Name を取得する。

    2. Setup API で、GUID_CLASS_USB_DEVICE の Device Information Set を取得し、GM_Get_DevNode_Status() で
        DN_REMOVABLE 属性を持つデバイスのみの Device Instance を抽出し、その Child Device に対して CM_Get_Device_ID(),
        CM_Get_Device_Interface_List() などの複数の Configuration API を駆使して、その Storage Device に対応する Instance Path を取得します。

    3. 上記 2 で Instance Path が取得出来たら、そのPath Name で GetVolumeNameForVolumeMountPoint() コールを行い、
        上記 1で取得した Volume Name と一致するモノを探します。
        つまり、Voluem Name が一致するものが、その USB Storage Device に対応する Drive Letter になるわけです。

    (残念ながら、上記1~3までの処理に関しては、WDK にサンプルはありません。)

    上記3で取得した Instance Path には、VID と PID の文字列が含まれているので、 そこから取得することもできますが、
    ちゃんと Device Descriptor から VID / PID を取得したいのであれば、さらにその Device Instance から対応する Hub Device の
    Device Instance を特定し、その Hub Device Instance から Instance Path を取得して、最終的に
    IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION で Device Descriptor の情報を取得する必要があります。
    この部分に関しては、USBView での実装が非常に参考になると思います。

    上記は、ホントに概要です。
    また、USB メモリ、USB CD-ROM、USB HDD, USB Floppy など Device Class に依存して、微妙に取得方法が変わってきますので、
    その点も考慮する必要があります。

    個人的にはかなり面倒だった記憶があり、ここでは書ききれません...
    少なくとも、上記に示されている単純なコードだけでは無理です。
    基本的な考え方は間違っていませんが、ポイントは USB Storage Device の Child Device として接続されている DevNode をチェックして
    行かないと、Drive Letter との関連は取得できないということです。
    つまり、GUID_CLASS_USB_DEVICE で列挙される Device Instnce は、あくまでも USB Device に対する Instance であり、
    Drive Letter との関連はsの Child Device である Volume クラスなどの DevNode で管理されている...ということだと思います。




    • 回答としてマーク 高橋 春樹 2010年2月22日 2:02
    • 回答としてマークされていない TDM850 4TX 2010年3月18日 9:48
    • 回答としてマーク TDM850 4TX 2010年5月15日 12:42
    2010年2月10日 8:28
  • TDM850 4TX さん、こんにちは。
    レスが遅くなってしまい申し訳ありません。

    ご質問の件につきまして、気がついたことを書いておきます。

    ☆ GetVolumeNameForVolumeMountPoint() について
    Source Code を見る限り、この関数の使い方は間違っていないと思いますが、1st パラメータの Volume Mount Point を
    示す文字列が null-terminated していないように見受けられます。
    MSDN のドキュメントには、null-terminated でないとダメ...とは書いてありませんが、NULL 終端の文字列でないとダメだったと思います。

    ☆ Instance Path について
    私の表現がちょっとおかしかったのかもしれませんね。
    私がここで言った Instance Path とは、VolumeClassGuid を指定して CM_Get_Device_Interface_List() をコールした
    際に取得される、 Interface Instance のことです。
    この CM_Get_Device_Interface_List() コールで取得された Interface Instance を  Volume Mount Point の Path として
    GetVolumeNameForVolumeMountPoint() をコールし、その結果取得される Volume Name を手順1で予め取得した Volume Name
    と比較し、一致するのが対応するドライブ レターと言うことです。
    CM_Get_Device_Interface_List() でエラーになるとのことですが、私の書いたコードと非常に良く似ているのですが、
    細かいところで若干異なっているので、理由はわかりません。
    ただ、CM_Get_Device_Interface_List() コールの際に指定する GUID や Device Instance ID が適切でないと、
    当然目的とする Interface Instance も取得されません。

    • 回答としてマーク 高橋 春樹 2010年2月22日 2:02
    • 回答としてマークされていない TDM850 4TX 2010年3月18日 9:47
    • 回答としてマーク TDM850 4TX 2010年3月18日 10:43
    • 回答としてマークされていない TDM850 4TX 2010年3月19日 8:30
    • 回答としてマーク TDM850 4TX 2010年5月15日 12:42
    2010年2月17日 1:28
  • TDM850 4TX さん、こんにちは。

    私の説明が少しおかしかったようですね。。。申し訳ありません。

    今回、F: ドライブに対して "\Device\Harddisk1\DP(1)0-0+4" の文字列が取得されたとのことですが、
    これは QueryDosDevice() コールで 1st パラメータに "F:\0" (F:) 等の DOS デバイス名を指定した場合に、
    2nd パラメータにかえされた Symbolic Link Name でしょうか?
    (おそらく、試された環境は XP だと思いますが...
      Volume Object を管理するドライバは、XP と Vista 以降の OS では異なっており、Vista / 7 環境で
      同様に QueryDosDevice() コールを行った場合、Symbolic Link Name として取得される名前は、
      "\Device\HarddiskVolumeXX" のような名前になると思います。)

    ドライブ レター情報を基に Volume Name を取得する場合には、TDM850 4TX さんが認識されていますように、
    GetVolumeNameForVolumeMountPoint() の 1st パラメータには "F:\\\0" (F:\) ようなドライブ レターの
    NULL 終端文字列を渡します。
    そうすると、2nd パラメータにセットしたバッファには、"\\?\Volume\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
    のような名前が返されてくるはずです。
    (ネットワーク ドライブの場合は返されません。)

    先の返信で QueryDosDevvice() の使用が必要と書きましたが、私の作ったサービス プログラムでは、USB ストレージ
    デバイスに割り当てられたドライブ レターの取得以外に、別途 Device Node 等のチェックが必要だったため、
    QueryDosDevice() 等の API を使用しています。 (説明が足りず、申し訳ありませんでした。)

    GUID には、GUID_DEVINTERFACE_USB_DEVICE を使用されているとのことですが、私の場合は先にも述べましたように、
    全ての USB デバイスの Device Node チェック等の必要があったため、SetupDiGetClassDevs() API では
    GUID_CLASS_USB_DEVICE を使用していいます。

    SetupDiGetClassDevs() で獲得した Device Information Set から個々の Device Instance を取得し、
    CM_Get_Child() で Child Device Node の中に "Volume" クラスが存在しているかを確認しています。
    チェック対象の USB デバイスが USB メモリや USB HDD の場合、その Child Device Node の中には必ず
    "Volume" クラスが介在するので、その Device Node から CM_GETIDLIST_FILTER_REMOVALRELATIONS に該当する
    Device Instance ID を割り出して、そこから最終的にドライブ レターを求める訳です。

    チェック対象の USB デバイスが Floppy や CD-ROM / DVD の場合は "Volume" クラスは介在しませんので、
    ちょっと処理を変える必要がありますが、基本的な考え方は同じです。

    ちなみに、GUID_DEVINTERFACE_USB_HOST_CONTROLLER はその名前の通り Host Controller 側の話なので、
    今回の場合関係ないと思います。

    • 回答としてマーク 高橋 春樹 2010年2月22日 2:02
    • 回答としてマークされていない TDM850 4TX 2010年3月18日 9:47
    • 回答としてマーク TDM850 4TX 2010年3月18日 10:43
    • 回答としてマークされていない TDM850 4TX 2010年3月19日 8:31
    • 回答としてマーク TDM850 4TX 2010年5月15日 12:42
    2010年2月18日 7:56
  • 再びこんばんわ。

    話がややこしくなりそうなので、USB メモリに限定して返信します。

    >CM_Get_Device_IDで取得した文字列で、
    > "USB\VID_xxxx&PID_xxxx\000000000000"
    >という値を取得できるのですが、この文字列の後尾に "\0" を付加して、
    >GetVolumeNameForVolumeMountPoint() を実行してもエラー(LastError:1)となります。

    "USB\VID_xxxx&PID_xxxx\000000000000" は USB デバイスの Instance ID で、Volume Device の Instance ID ではありません。
    なので GetVolumeNameForVolumeMountPoint() のパラメータにはなりません。
    USB メモリの場合、その上に "DiskDrive" のデバイス クラスがあるはずなので、そこまで辿って行く必要があります。


    >全てのデバイスを CM_Get_Child()を使って再起コールにて検索し、
    >CM_Get_Device_Interface_List() で取得した文字列は
    > "\\?\STORAGE#RemovableMedia#7&847c7dd&0&RM#{GUID}\"
    >となりこちらは GetVolumeNameForVolumeMountPoint() を実行してもエラーとならず、
    >ドライブレターで GetVolumeNameForVolumeMountPoint() を実行した文字列と一致します。

    USB Floppy などは USBStor の上位が "DiskDrive" のデバイス クラスにならないので、CM_GetDevice_ID_List() の
    CM_GETIDLIST_FILTER_REMOVALRELATIONS からたどっていく必要があります。


    >疑問①
    >VID/PIDが入っている時の DEVINSTと、
    >Volumeクラスを検出できた時の DEVINST をマッチさせる方法が分かりませんでした。

    何度も言うようですが、そこが一番「肝」なのです。
    USB メモリの場合、"DiskDrive" デバイス クラスの Device Instance Handle (DEVINST) が取得出来たら、
    CM_Get_Device_ID() でその DiskDrive デバイスの Device Instance ID を取得します。
    これに成功すると、
    "USBSTOR\DISK&VEN_xxxx&PROD_xxxx...."
    と言う感じの Device Instance ID が CM_Get_Device_ID() の 2nd パラメータに返されます。。
    次に、CM_Get_Device_Interface_List() の 1st パラメータに VolumeClassGuid (GUID_DEVINTERFACE_VOLUME) へのポインタと、
    2nd パラメータに上記で取得した "USBSTOR\DISK&VEN_xxxx&PROD_xxxx...." で示される DiskDrive デバイスの Device Instance ID
    をそれぞれセットしてコールします。
    (この時、あらかじめ CM_Get_Device_Interface_List_Size() でバッファ サイズを取得しておく必要があります。)
    そうすると、3rd パラメータにセットしたバッファに、"\\?\Volume\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\" の Volume Name が
    返されるはずです。
    これでやっと、USB メモリ デバイスに対応する Volume Device が特定できる訳です。


    >疑問②
    >USBView では、HubDeviceをハンドルとして IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX をかけていますが、
    >DEVINST からハンドルを生成する方法はあるのでしょうか?

    何がしたいのか、質問の意味を把握しかねますが...
    例えば、"USB\VID_xxxx&PID_xxxx\000000000000" で示される USB デバイスの Instance ID に対応する Device Instance Handle から、
    それに対応する Hub Device のハンドルが欲しいのであれば、CM_Get_Parent() で Hub Device の Device Instance Handle を取得し、
    そこから CM_Get_Device_ID() で Device Instance ID 取得し、その名前で最終的に CreateFile() をすれば、取得できると思います。


    >GUID_CLASS_USB_DEVICE と GUID_DEVINTERFACE_USB_DEVICE は同じ値でした。

    TDM850 4TX さんがご指摘されている通りですね。
    大変失礼いたしました。


    ちなみに、すぐに返事を期待されてもむりですよ。
    私にも「私の仕事」があり忙しいですので。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年3月23日 9:17
  • 再びこんばんわ。
    うーん。。。ちょっとまだ理解してもらえていないよなので、気になった点をいくつか...

    > "\\?\STORAGE#RemovableMedia#xxxxxxxxxxxxxx#{GUID}\"ではキーに使えないため
    > 取得情報が違う。

    前回示した方法は、USB メモリの場合のデバイスとボリュームを関連付ける方法です。
    USB メモリ / HDD 以外のストレージ、例えば Floppy や CD-ROM / DVD などは、
    "\\?\STORAGE#RemovableMedia#xxxxxxxxxxxxxx#{GUID}\" の方からやらないと、だめです。
    少なくとも私の実装では、USB メモリ / HDD と、Floppy / CD-ROM / DVD では、
    "USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz" という USB デバイスの Device Instance ID を取得
    するところまでは一緒ですが、そこからドライブ レターとの関連付け情報を取得するところが異なります。
    まずは、USB メモリ / HDD など、USBSTOR の上位が DiskDrive クラスになるデバイスに特化して
    実装をすることをお勧めします。
    (それが出来れば、Floppy / CD-ROM / DVD などの場合にどう実装すれば良いのかわかりやすくなるので。)

    >"VEN_BUFFALO" が取得されます。
    >当方としては、"VID_0411" 形式のベンダーIDが欲しいのです。

    とても大雑把ですが....
    例えば今、"USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz" という USB デバイスの Device Instance ID が取得できたとします。
    この USB デバイスが USB メモリ / HDD である場合、その上位のデバイス クラスは "DiskDrive" になります。
    なので、"USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz" に対応する Device Instance Handle (DEVINST) をパラメータに
    CM_Get_Child() をコールして、USB デバイスの上位のデバイス クラス (要するに Child Device) の DEVINST を取得
    します。

    -------------------------------
    1. USB デバイスの Device Instance ID ("USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz") に対応する DEVINST で
       CM_Get_Child() コールを行い、Child Device の DEVINST を取得。
    -------------------------------

    取得出来たら、それが "DiskDrive" かどうかを確認した方が良いかもしれません。
    (以降の処理でエラーになったら 「USB メモリ / HDD ではない」と判別出来ればいいだけなので、必須ではありません。)
    "DiskDrive" クラスかどうかの確認には、SetupDiGetDeviceRegistryProperty() などの API の使用が必要になります。
    必須ではないので、ここでは割愛します。

    次に、Child Device ("DiskDrive" クラス) の Device Instance ID を取得します。

    -------------------------------
    2. Child Device の DEVINST で CM_Get_Device_ID() をコールして Device Instance ID を取得。
    -------------------------------

    "DiskDrive" クラス の Device Instance ID の場合、"USBSTOR\DISK&VEN_xxxx&PROD_xxxx...." という
    Instance ID が取得出来るはずです。
    後は、前回書いた下記の処理を行えば、、
    "\\?\Volume\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
    という Volume Name が取得出来るはずです。
    (取得できなかったら、その Child Device は "DiskDrive" クラスではないので、USB メモリ / HDD ではない...ということです。)

    -------------------------------
    >CM_Get_Device_Interface_List() の 1st パラメータに VolumeClassGuid (GUID_DEVINTERFACE_VOLUME) へのポインタと、
    >2nd パラメータに上記で取得した "USBSTOR\DISK&VEN_xxxx&PROD_xxxx...." で示される DiskDrive デバイスの Device Instance ID
    >をそれぞれセットしてコールします。
    -------------------------------

    > USBViewでは DeviceIoControl()で VID/PIDを取得していたので、
    > HubDeviceのハンドルが必要だと思っていました。

    ちゃんと USB デバイスの Device Descriptor から Vender ID / Product ID / Serial Number を取得したい
    のであれば、TDM850 4TX さんが認識されているように、HubDevice のハンドルが必須になります。
    ちなみに、USB デバイスの Device Instance ID である "USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz" は、

    xxxx : Vendor ID
    yyyy : Product ID
    zzzzzzzzzzzz : Serial Number

    になってたはずです。
    ただし、Serial Number をサポートしないデバイス、あるいは Windows 側のレジストリ設定で Serial Number に
    よる識別を無効にしている場合には、"zzzzzzzzzzzz" の部分は別の文字列になります。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年3月24日 12:15
  • 全く検証していませんが、以下のような感じの処理を追加すれば、うまくいくはずです。

    -----------------------------------------------------------------------
    #include "stdafx.h"
    #include <windows.h>
    #include <setupapi.h> // SetupDixxx
    #include <Cfgmgr32.h> // CM_Get_xxx

    #pragma comment( lib, "setupapi.lib" )
    #pragma comment( lib, "Cfgmgr32.lib" )


    static /*const*/ GUID GUID_DEVINTERFACE_USB_DEVICE =
    { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };

    void StrConv2Upper( char *pszStr );


    int _tmain(int argc, _TCHAR* argv[])
    {
     DWORD dwRet;
     TCHAR strDrive[8];
     TCHAR pszPhysicalDeviceName[MAX_PATH];
     TCHAR pszVolumeName[MAX_PATH];

    /* ■1 ドライブから物理名とボリューム名を取得 */
     sprintf_s( strDrive, sizeof(strDrive), "E:\\" );
     UINT drvType = GetDriveType( strDrive );
     if( drvType == DRIVE_REMOVABLE )
     { // リムーバブルのみ
      strDrive[2] = NULL;
      dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
      if(dwRet == 0)
      {
       printf( "QueryDosDevice() Error! [%d]\n", GetLastError() );
       return 1;
      }
      printf("PhysicalDeviceName[%s]\n", pszPhysicalDeviceName );

      // ボリューム名を取得
      strDrive[2] = '\\';
      strDrive[3] = NULL;
      dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszVolumeName, MAX_PATH );
      if( dwRet == 0 )
      {
       printf( "GetVolumeNameForVolumeMountPoint() Error! [%d]\n", GetLastError() );
       return 1;
      }
      printf("Note:VolumeName[%s]\n", pszVolumeName );
     }
     else
     {
      printf("Not REMOVABLE\n", strDrive );
      return 1;
     }


    /* ■2 Device Instance を取得 */
     HDEVINFO     DeviceInfoTable = INVALID_HANDLE_VALUE;
     SP_DEVICE_INTERFACE_DATA DevInterfaceData;
     SP_DEVINFO_DATA    DevInfoData;

     DWORD InterfaceIndex = 0;
     DWORD StatusLastError = 0;
     DWORD RegType;
     DWORD RegSize;   //使いまわしあり
     DWORD StructureSize = 0;
     PBYTE PropertyValueBuffer = NULL;
     bool MatchFound = false;
     DWORD ErrorStatus;

     ZeroMemory(&DevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
     DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);


     // USBデバイス用の情報セットを取得
     DeviceInfoTable = SetupDiGetClassDevs( &GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );

     while( !MatchFound )
     {
      DevInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
      if( SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &GUID_DEVINTERFACE_USB_DEVICE, InterfaceIndex, &DevInterfaceData) )
      {
       ErrorStatus = GetLastError();
       if( ERROR_NO_MORE_ITEMS == ErrorStatus )
       { //情報セットの終端
        break;
       }
      }
      else
      { // 予期していないエラー。基本的に起こりえないと思われる
       ErrorStatus = GetLastError();
       break;
      }

      // USBデバイス情報の詳細を取得
      DevInfoData.cbSize = sizeof( SP_DEVINFO_DATA );
      SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData);

      // 詳細情報のデータを取得
      SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, NULL, 0, &RegSize );
      PropertyValueBuffer = (BYTE*) malloc( RegSize * sizeof(BYTE) );
      SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, PropertyValueBuffer, RegSize, NULL );

      StrConv2Upper((char*)PropertyValueBuffer);
      printf("PropertyValueBuffer[%s]\n", PropertyValueBuffer );

      if( (strstr((char*)PropertyValueBuffer, "VID_0411&PID_0") != NULL)
        ||
       (strstr((char*)PropertyValueBuffer, "VID_0411&PID_1") != NULL)
        )
       { // BUFFALO Device
       MatchFound = true;

       // ここからはドライブレターとのマッチングで使用する情報を取得する

       // VID/PIDが一致した DEVINSTを使用して
       // "DiskDrive" デバイス クラスの Device Instance Handleを取得する
       DEVINST  devInstChild;
       dwRet = CM_Get_Child( &devInstChild, DevInfoData.DevInst, 0 );
       if( dwRet != CR_SUCCESS )
       {
        printf( "CM_Get_Child() Err.[%d][%d]\n", dwRet, GetLastError() );
        goto EndLabel;
       }

       TCHAR pszDevInstanceId[MAX_PATH];
       dwRet = CM_Get_Device_ID( devInstChild, pszDevInstanceId, MAX_PATH, 0 );
       if( dwRet != CR_SUCCESS )
       {
        printf( "CM_Get_Device_ID() Err.[%d][%d]\n", dwRet, GetLastError() );
        goto EndLabel;
       }
       printf("pszDevInstanceId[%s]\n", pszDevInstanceId );


       // Instance Pathを取得する
       ULONG ulSize;
    #if 0
       dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&DiskClassGuid, pszDevInstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
    #else
    // ====>
       dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&VolumeClassGuid, pszDevInstanceId, 0 );
    // <====
    #endif
       if( dwRet != CR_SUCCESS )
       {
        printf( "CM_Get_Device_Interface_List_Size() Err.[%d][%d]\n", dwRet, GetLastError() );
        goto EndLabel;
       }
       printf("CM_Get_Device_Interface_List_Size[%d]\n", ulSize );


       RegSize = (ulSize * sizeof(TCHAR)) +1; // +1:GetVolumeNameForVolumeMountPoint()で 最後に '\'が必要なため
       LPTSTR pszList = (LPTSTR) malloc( RegSize );
       if( pszList == NULL )
       {
        printf( "malloc() Err.[%d][%d]\n", RegSize, GetLastError() );
        goto EndLabel;
       }

    #if 0
       dwRet = CM_Get_Device_Interface_List( (LPGUID)&DiskClassGuid, pszDevInstanceId, (PCHAR)pszList, ulSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
    #else
    // ====>
       dwRet = CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pszDevInstanceId, (PCHAR)pszList, ulSize, 0 );
    // <====
    #endif
       if( dwRet != CR_SUCCESS )
       {
        printf( "CM_Get_Device_Interface_List() Err.[%d][%d]\n", dwRet, GetLastError() );
        free(pszList);
        goto EndLabel;
       }
       printf("Instance Path[%s]\n", pszList );


    #if 1
    // ====>
       if ( *pszList == NULL )
       {
        ULONG   ulDeviceIDsListSize       = 0;
        ULONG   ulDeviceInterfaceListSize = 0;
        PTCHAR  pDeviceIDsList            = NULL;
        PTCHAR  pDeviceInterfacesList     = NULL;

        if( CM_Get_Device_ID_List_Size( &ulDeviceIDsListSize, pszDevInstanceId, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
        {
         ulDeviceIDsListSize *= sizeof(TCHAR);
         pDeviceIDsList = malloc( ulDeviceIDsListSize );

         if ( pDeviceIDsList )
         {
          if( CM_Get_Device_ID_List( pszDevInstanceId, pDeviceIDsList, ulDeviceIDsListSize, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
          {
           if ( CM_Get_Device_Interface_List_Size( &ulDeviceInterfaceListSize, (LPGUID)&VolumeClassGuid, pDeviceIDsList, 0 ) == CR_SUCCESS )
           {
            ulDeviceInterfaceListSize *= sizeof(TCHAR);
            pDeviceInterfacesList = malloc( ulDeviceInterfaceListSize );
            if ( pDeviceInterfacesList )
            {
             if ( CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pDeviceIDsList, (PCHAR)pDeviceInterfacesList, ulDeviceInterfaceListSize, 0 ) == CR_SUCCESS )I
             {
              free(pszList);
              pszList = NULL;
              RegSize = 0;

              RegSize = ulDeviceInterfaceListSize + sizeof( TCHAR );
              pszList = malloc( RegSize );
                                            ZeroMemory( pszList, RegSize );
                                            CopyMemory( pszList, pDeviceInterfacesList, ulDeviceInterfaceListSize);
             }
             free( pDeviceInterfacesList );
            }
           }
          }
          free( pDeviceIDsList );
         }
        }
       }
    // <====
    #endif


       ulSize = (DWORD)strnlen( pszList, RegSize );
       pszList[ulSize] = '\\';
       pszList[ulSize+1] = NULL;
       printf("Instance Path2[%d][%s]\n", ulSize, pszList );

       dwRet = GetVolumeNameForVolumeMountPoint( pszList, pszVolumeName, MAX_PATH );
       if( dwRet == 0 )
       {
        printf( "GetVolumeNameForVolumeMountPoint() Error! [%d]\n", GetLastError() );
        free(pszList);
        goto EndLabel;
       }
       printf("Note:VolumeName[%s]\n", pszVolumeName );
       free(pszList);
      }
    EndLabel:
      free(PropertyValueBuffer);
      InterfaceIndex++;

      }//while(MatchFound) 

     SetupDiDestroyDeviceInfoList( DeviceInfoTable );

     return 0;
    }

    /* 文字列中の英小文字を大文字に変換 */
    void StrConv2Upper( char *pszStr )
    {
     char *p;
     for (p = pszStr; *p; p++)
      *p = toupper(*p);
     return;
    } // StrConv2Upper
    -----------------------------------------------------------------------

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年4月7日 4:59
  • コマンド プロンプトで、"MountVol" を実行してみてください。

    現在のマウント ポイントとボリューム名の一覧が表示されます。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年4月7日 5:42
  • "\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"

    ↑ これはどのドライブ レターのモノでしたか?

    また、そのドライブ レターが割り当てられているデバイスは何ですか?

    おそらく E: 以外に、別の USB ストレージ デバイスが接続されているためと思われます。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年4月7日 7:28
  • MountVol コマンドの出力結果に、以下のマウント ポイントは出力されていないのですか?

    "\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"

    また、使用している USB デバイスの種類は何でしょうか?

    1つの USB デバイスでも、複数のインターフェイス (ボリューム等)をもつものあります。

    デバイスが1つだけだからと言って、ボリュームが1つだけとは限りません。

    とにかく、MountVol での出力結果を見ないと、なんとも言えません。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年4月7日 9:11
  • >"\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"
    >ですが、表示されていないです。
    ↑ C: ドライブのボリューム名ではないのでしょうか?

    以下の処理を確認してみてはいかがでしょう?

    if ( CM_Get_Device_Interface_List_Size( &ulDeviceInterfaceListSize, (LPGUID)&VolumeClassGuid, pDeviceIDsList, 0 ) == CR_SUCCESS )
    ↑ このコールの時に pszDevInstanceId と pDeviceIDsList にセットされている文字列と、ulDeviceInterfaceListSize に返されたサイズ。

    C: ドライブは内蔵 HDD とのことなので、下側のバスは IDE/ATA もしくは AHCI なるはずだと思います。
    ですので、GUID GUID_DEVINTERFACE_USB_DEVICE を指定して C: ドライブのボリューム名が取得されるのは、
    根本的プログラムのロジックがおかしいため...と思います。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月8日 5:46
  • 返信が遅くなってしまったので、既に解決してるかもしれませんが。。。

    たぶん、単純に文字列操作に問題があるんだと思います。

    少なくとも、ストレージ デバイスがUSBメモリなら、先に示した感じの実装で必ずボリューム名が取れるはずです。

    strstr() での文字列チェックの所で、ちゃんと判別できているかを再度確認するのが先決だと思います。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月15日 11:05
  • とりあえず、私の環境で動作を確認したコードを以下に添付します。
    (USB メモリおよび USB フロッピーで正常に動作することを確認しています。)
    ご覧いただければご理解いただけると思いますが、このコードの基本ロジックは、
    先に示したものと全く同一です。
    変更した箇所は、以下の部分だけです。

    ☆ UNICODE 対応
    ☆ ドライブ レターおよびハードウェア ID を任意に指定できるようパラメータ処理の追加。

    先に TDM850 4TX さんが示されたコードと全く同じ条件下で実行するのであれば、以下のパラメータで実行してください。

    <ProgrameName> E: "VID_0411&PID_0"

    元々は TDM850 4TX さんが示されたコードなのであえて説明は必要ないかと思いますが、
    ドライブ レターに対応するストレージ デバイスのハードウェア ID が、プログラム実行時の 2nd パラメータと一致すると、
    以下の一文を出力するようにしてあります。

    "!!!! Target volume devie is found !!!!"

    なお、私は WDK のビルド環境を使用してビルドしましので、ヘッダー ファイルおよびライブラリ ファイルに関しては
    適宜変更してください。

    もし、仮にこれで正常に機能しない場合は、もっと別のところに問題があると思います。

     

    #define UNICODE
    #define _UNICODE
    
    #include <stdio.h>
    #include <malloc.h>
    #include <windows.h>
    #include <tchar.h>
    #include <setupapi.h> // SetupDixxx
    #include <Cfgmgr32.h> // CM_Get_xxx
    #include <initguid.h>
    #include <winioctl.h>
    #include <usbiodef.h>
    
    
    #pragma comment( lib, "setupapi.lib" )
    #pragma comment( lib, "Cfgmgr32.lib" )
    
    #define NICO_CHAN_TEST TRUE
    
    
    void Usage
    (
      PTSTR  BinaryName
    )
    {
      _tprintf( (TEXT("\n")
            TEXT("Usage:                \n")
            TEXT("   %s <drive:> <VID_xxxx&PID_xxxx> \n")
            TEXT("Ex.]                 \n")
            TEXT("   %s E: \"VID_0411&PID_0\"    \n")), BinaryName, BinaryName );
    }
    
    
    int __cdecl _tmain
    (
      int argc, 
      TCHAR* argv[]
    )
    {
      DWORD  dwRet;
      TCHAR  strDrive[8];
      TCHAR  pszPhysicalDeviceName[MAX_PATH];
      TCHAR  pszTargetVolumeName[MAX_PATH];
      TCHAR  pszVolumeName[MAX_PATH];
    
    //_asm int 3;
    
      /* ■1 ドライブから物理名とボリューム名を取得 */
    #if !NICO_CHAN_TEST
      wsprintf( strDrive, TEXT("E:\\") );
    #else
      PTSTR  tstrHardwareID;
    
      if ( argc != 3 )
      {
        Usage( argv[0] );
        return 1;
      }
      else
      {
        TCHAR  DriveLetter = argv[1][0];
    
        if ( !(( DriveLetter >= _T('a') && DriveLetter <= _T('z') ) ||
            ( DriveLetter >= _T('A') && DriveLetter <= _T('Z') )) ||
           ( argv[1][1] != _T(':')) || ( argv[1][2] != _T('\0') ) )
        {
          Usage( argv[0] );
          return 1;
        }
      }
    
      _tprintf( TEXT("Target Drive : [%s]\n"), argv[1] );
      wsprintf( strDrive, TEXT("%s\\"), argv[1] );
    
      tstrHardwareID = argv[2];
    #endif
    
      UINT drvType = GetDriveType( strDrive );
    
      if( drvType == DRIVE_REMOVABLE )
      { // リムーバブルのみ
        strDrive[2] = NULL;
        dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
        if(dwRet == 0)
        {
          _tprintf( TEXT("QueryDosDevice() Error! [%d]\n"), GetLastError() );
          return 1;
        }
    
        _tprintf( TEXT("Physical Device Name : [%s]\n"), pszPhysicalDeviceName );
    
        // ボリューム名を取得
        strDrive[2] = '\\';
        strDrive[3] = NULL;
        dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszTargetVolumeName, MAX_PATH );
    
        if( dwRet == 0 )
        {
          _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
          return 1;
        }
    
        _tprintf( TEXT("!!! Note !!!\n")
             TEXT("\tTargetVolumeName : [%s]\n\n"), pszTargetVolumeName );
      }
      else
      {
        _tprintf( TEXT("Not REMOVABLE\n"), strDrive );
        return 1;
      }
    
    
      /* ■2 Device Instance を取得 */
      HDEVINFO          DeviceInfoTable = INVALID_HANDLE_VALUE;
      SP_DEVICE_INTERFACE_DATA  DevInterfaceData;
      SP_DEVINFO_DATA       DevInfoData;
    
      DWORD  InterfaceIndex = 0;
      DWORD  StatusLastError = 0;
      DWORD  RegType;
      DWORD  RegSize;  //使いまわしあり
      DWORD  StructureSize = 0;
      PBYTE  PropertyValueBuffer = NULL;
      BOOL  MatchFound = false;
      DWORD  ErrorStatus;
    
      ZeroMemory(&DevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
      DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    
    
      // USBデバイス用の情報セットを取得 
      DeviceInfoTable = SetupDiGetClassDevs( &GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
      if ( DeviceInfoTable == INVALID_HANDLE_VALUE )
      {
        _tprintf( TEXT("DeviceInfoTable == INVALID_HANDLE_VALUE \n") );
        return 1;
      }
    
      while( !MatchFound )
      {
        DevInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
        if( SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &GUID_DEVINTERFACE_USB_DEVICE, InterfaceIndex, &DevInterfaceData) )
        {
          ErrorStatus = GetLastError();
          if( ERROR_NO_MORE_ITEMS == ErrorStatus )
          { //情報セットの終端
            break;
          }
        }
        else
        { // 予期していないエラー。基本的に起こりえないと思われる
          ErrorStatus = GetLastError();
          break;
        }
    
        // USBデバイス情報の詳細を取得
        DevInfoData.cbSize = sizeof( SP_DEVINFO_DATA );
        SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData);
    
        // 詳細情報のデータを取得
        SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, NULL, 0, &RegSize );
        PropertyValueBuffer = (BYTE*) malloc( RegSize * sizeof(BYTE) );
        SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, PropertyValueBuffer, RegSize, NULL );
    
        CharUpper( (PTCHAR)PropertyValueBuffer );
    
        _tprintf( TEXT("Hardware ID : [%s]\n"), PropertyValueBuffer );
    
    #if !NICO_CHAN_TEST
        // BUFFALO Device
        if( (_tcsstr( (PTCHAR)PropertyValueBuffer, TEXT("VID_0411&PID_0") ) != NULL) ||
          (_tcsstr( (PTCHAR)PropertyValueBuffer, TEXT("VID_0411&PID_1") ) != NULL) )
    #else
        CharUpper( (PTCHAR)tstrHardwareID );
        if( (_tcsstr( (PTCHAR)PropertyValueBuffer, tstrHardwareID ) != NULL) )
    #endif NICO_CHAN_TEST
        {
    
          // ここからはドライブレターとのマッチングで使用する情報を取得する
    
          // VID/PIDが一致した DEVINSTを使用して
          // "DiskDrive" デバイス クラスの Device Instance Handleを取得する
          DEVINST devInstChild;
          dwRet = CM_Get_Child( &devInstChild, DevInfoData.DevInst, 0 );
          if( dwRet != CR_SUCCESS )
          {
            _tprintf( TEXT("CM_Get_Child() Err.[%d][%d]\n"), dwRet, GetLastError() );
            goto EndLabel;
          }
    
          TCHAR pszDevInstanceId[MAX_PATH];
    
          dwRet = CM_Get_Device_ID( devInstChild, pszDevInstanceId, MAX_PATH, 0 );
          if( dwRet != CR_SUCCESS )
          {
            _tprintf( TEXT("CM_Get_Device_ID() Err.[%d][%d]\n"), dwRet, GetLastError() );
            goto EndLabel;
          }
          _tprintf( TEXT("Device Instance ID : [%s]\n"), pszDevInstanceId );
    
    
          // Instance Pathを取得する
          ULONG ulSize;
    
          dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&VolumeClassGuid, pszDevInstanceId, 0 );
          if( dwRet != CR_SUCCESS )
          {
            _tprintf( TEXT("CM_Get_Device_Interface_List_Size() Err.[%d][%d]\n"), dwRet, GetLastError() );
            goto EndLabel;
          }
          _tprintf( TEXT("CM_Get_Device_Interface_List_Size[%d]\n"), ulSize );
    
    
          RegSize = (ulSize * sizeof(TCHAR)) +1; // +1:GetVolumeNameForVolumeMountPoint()で 最後に '\'が必要なため
          LPTSTR pszList = (LPTSTR) malloc( RegSize );
    
          if( pszList == NULL )
          {
            _tprintf( TEXT("malloc() Err.[%d][%d]\n"), RegSize, GetLastError() );
            goto EndLabel;
          }
    
          dwRet = CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pszDevInstanceId, pszList, ulSize, 0 );
    
          if( dwRet != CR_SUCCESS )
          {
            _tprintf( TEXT("CM_Get_Device_Interface_List() Err.[%d][%d]\n"), dwRet, GetLastError() );
            free(pszList);
            goto EndLabel;
          }
          _tprintf( TEXT("Instance Path : [%s]\n"), pszList );
    
    
    #if 1
    // ====> 
          if ( *pszList == NULL )
          {
            ULONG  ulDeviceIDsListSize    = 0;
            ULONG  ulDeviceInterfaceListSize = 0;
            PTCHAR pDeviceIDsList      = NULL;
            PTCHAR pDeviceInterfacesList   = NULL;
    
            if( CM_Get_Device_ID_List_Size( &ulDeviceIDsListSize, pszDevInstanceId, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
            {
              ulDeviceIDsListSize *= sizeof(TCHAR);
              pDeviceIDsList = (PTCHAR)malloc( ulDeviceIDsListSize );
    
              if ( pDeviceIDsList )
              {
                if( CM_Get_Device_ID_List( pszDevInstanceId, pDeviceIDsList, ulDeviceIDsListSize, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
                {
                  if ( CM_Get_Device_Interface_List_Size( &ulDeviceInterfaceListSize, (LPGUID)&VolumeClassGuid, pDeviceIDsList, 0 ) == CR_SUCCESS )
                  {
                    ulDeviceInterfaceListSize *= sizeof(TCHAR);
                    pDeviceInterfacesList = (PTCHAR)malloc( ulDeviceInterfaceListSize );
                    if ( pDeviceInterfacesList )
                    {
                      if ( CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pDeviceIDsList, pDeviceInterfacesList, ulDeviceInterfaceListSize, 0 ) == CR_SUCCESS )
                      {
                        free(pszList);
                        pszList = NULL;
                        RegSize = 0;
    
                        RegSize = ulDeviceInterfaceListSize + sizeof( TCHAR );
                        pszList = (PTCHAR)malloc( RegSize );
                        ZeroMemory( pszList, RegSize );
                        CopyMemory( pszList, pDeviceInterfacesList, ulDeviceInterfaceListSize);
                      }
                      free( pDeviceInterfacesList );
                    }
                  }
                }
                free( pDeviceIDsList );
              }
            }
          }
    // <==== 
    #endif
    
    
          ulSize = _tcslen( pszList );
          pszList[ulSize] = '\\';
          pszList[ulSize+1] = NULL;
          _tprintf( TEXT("Instance Path2[%d] : [%s]\n"), ulSize, pszList );
    
          dwRet = GetVolumeNameForVolumeMountPoint( pszList, pszVolumeName, MAX_PATH );
          if( dwRet == 0 )
          {
            _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
            free(pszList);
            goto EndLabel;
          }
    
          _tprintf( TEXT("VolumeName : [%s]\n"), pszVolumeName );
    
          if ( !(_tcsnicmp( pszVolumeName, pszTargetVolumeName, _tcslen(pszTargetVolumeName) )) )
          {
            _tprintf( TEXT("!!! Note !!!\n") );
            _tprintf( TEXT("\tHardware ID    : [%s]\n"), PropertyValueBuffer );
            _tprintf( TEXT("\tSymbolic Link Name : [%s]\n"), pszList );
            _tprintf( TEXT("\tVolumeName     : [%s]\n"), pszVolumeName );
            _tprintf( TEXT("!!!! Target volume devie is found !!!!\n") );
            MatchFound = true;
          }
     
          free(pszList);
        }
    
    EndLabel:
        free(PropertyValueBuffer);
        InterfaceIndex++;
    
      }//while(MatchFound) 
    
      SetupDiDestroyDeviceInfoList( DeviceInfoTable );
    
      return 0;
    }
    
    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月20日 5:04
  • USB メモリで試すとどうなりますか?

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月23日 1:23
  • プログラム実行時のパラメータ指定はどのようにされているのでしょうか?
    プログラム実行時のパラメータ入力も示して頂けますか?

    (上記ログを見ると、2nd パラメータで指定した "VID_xxxx&PID_xxxx" と合致していないように見受けられます。
      VID / PID の指定部分は Double Quotation '"' で囲っているのでしょうか?)

    先に示したコードをそのまま使っているのであれば、少なくとも USB メモリではうまく動くはずです。
    実際、動作検証を行ったコードをそのままコピペしましたので...

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月28日 0:55
  • デバッガ上でちゃんと確認されているのでしょうか?

     

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年5月6日 16:17
  • 再びこんばんは。

    >適宜ライブラリを変更するようにとのことですが、使用するバージョンは関係しますでしょうか。

    WDK のバージョンに依存した問題ではないと思います。
    先に示したコードは、USB メモリでのみ検証したもので、USB HDD の場合を考慮していません。
    ただ、通常の USB メモリでもうまく動作しないのが、私としては非常に不思議なのですが....

    USB HDD の場合、兄弟デバイスをチェックする必要があります。

    一応、下記コードで USB メモリと USB HDD および USB CD-ROM ドライブで正しく機能することを確認しましたので、
    試してみてください。

    ------------------------------------------------------------------------------
    #define UNICODE
    #define _UNICODE

    #include <stdio.h>
    #include <malloc.h>
    #include <windows.h>
    #include <tchar.h>
    #include <setupapi.h> // SetupDixxx
    #include <Cfgmgr32.h> // CM_Get_xxx
    #include <initguid.h>
    #include <winioctl.h>
    #include <usbiodef.h>


    #pragma comment( lib, "setupapi.lib" )
    #pragma comment( lib, "Cfgmgr32.lib" )

    #define NICO_CHAN_TEST  TRUE


    void Usage
    (
        PTSTR   BinaryName
    )
    {
        _tprintf( (TEXT("\n")
                   TEXT("Usage:                                \n")
                   TEXT("      %s <drive:> <VID_xxxx&PID_xxxx> \n")
                   TEXT("Ex.]                                  \n")
                   TEXT("      %s E: \"VID_0411&PID_0\"        \n")), BinaryName, BinaryName );
    }


    int __cdecl _tmain
    (
        int argc,
        TCHAR* argv[]
    )
    {
        DWORD   dwRet;
        TCHAR   strDrive[8];
        TCHAR   pszPhysicalDeviceName[MAX_PATH];
        TCHAR   pszTargetVolumeName[MAX_PATH];
        TCHAR   pszVolumeName[MAX_PATH];

    //_asm int 3;

        /* ■1 ドライブから物理名とボリューム名を取得 */
    #if !NICO_CHAN_TEST
        wsprintf( strDrive, TEXT("E:\\") );
    #else
        PTSTR   tstrHardwareID;

        if ( argc != 3 )
        {
            Usage( argv[0] );
            return 1;
        }
        else
        {
            TCHAR   DriveLetter = argv[1][0];

            if ( !(( DriveLetter >= _T('a') && DriveLetter <= _T('z') )  ||
                   ( DriveLetter >= _T('A') && DriveLetter <= _T('Z') )) ||
                  ( argv[1][1] != _T(':')) || ( argv[1][2] != _T('\0') ) )
            {
                Usage( argv[0] );
                return 1;
            }
        }

        _tprintf( TEXT("Target Drive : [%s]\n"), argv[1] );
        wsprintf( strDrive, TEXT("%s\\"), argv[1] );

        tstrHardwareID = argv[2];
    #endif

        UINT drvType = GetDriveType( strDrive );

    #if 0
        if( drvType == DRIVE_REMOVABLE )
        { // リムーバブルのみ
            strDrive[2] = NULL;
            dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
            if(dwRet == 0)
            {
                _tprintf( TEXT("QueryDosDevice() Error! [%d]\n"), GetLastError() );
                return 1;
            }

            _tprintf( TEXT("Physical Device Name : [%s]\n"), pszPhysicalDeviceName );

            // ボリューム名を取得
            strDrive[2] = '\\';
            strDrive[3] = NULL;
            dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszTargetVolumeName, MAX_PATH );

            if( dwRet == 0 )
            {
                _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
                return 1;
            }

            _tprintf( TEXT("!!! Note !!!\n")
                      TEXT("\tTargetVolumeName : [%s]\n\n"), pszTargetVolumeName );
        }
        else
        {
            _tprintf( TEXT("Not REMOVABLE\n"), strDrive );
            return 1;
        }
    #else
        strDrive[2] = NULL;
        dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
        if(dwRet == 0)
        {
            _tprintf( TEXT("QueryDosDevice() Error! [%d]\n"), GetLastError() );
            return 1;
        }

        _tprintf( TEXT("Physical Device Name : [%s]\n"), pszPhysicalDeviceName );

        // ボリューム名を取得
        strDrive[2] = '\\';
        strDrive[3] = NULL;
        dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszTargetVolumeName, MAX_PATH );

        if( dwRet == 0 )
        {
            _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
            return 1;
        }

        _tprintf( TEXT("!!! Note !!!\n")
                  TEXT("\tTargetVolumeName : [%s]\n\n"), pszTargetVolumeName );
    #endif

        /* ■2 Device Instance を取得 */
        HDEVINFO                    DeviceInfoTable = INVALID_HANDLE_VALUE;
        SP_DEVICE_INTERFACE_DATA    DevInterfaceData;
        SP_DEVINFO_DATA             DevInfoData;

        DWORD   InterfaceIndex = 0;
        DWORD   StatusLastError = 0;
        DWORD   RegType;
        DWORD   RegSize;   //使いまわしあり
        DWORD   StructureSize = 0;
        PBYTE   PropertyValueBuffer = NULL;
        BOOL    MatchFound = false;
        DWORD   ErrorStatus;

        ZeroMemory(&DevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
        DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);


        // USBデバイス用の情報セットを取得
        DeviceInfoTable = SetupDiGetClassDevs( &GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
        if ( DeviceInfoTable == INVALID_HANDLE_VALUE )
        {
            _tprintf( TEXT("DeviceInfoTable == INVALID_HANDLE_VALUE \n") );
            return 1;
        }

        while( !MatchFound )
        {
            DevInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
            if( SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &GUID_DEVINTERFACE_USB_DEVICE, InterfaceIndex, &DevInterfaceData) )
            {
                ErrorStatus = GetLastError();
                if( ERROR_NO_MORE_ITEMS == ErrorStatus )
                { //情報セットの終端
                    break;
                }
            }
            else
            { // 予期していないエラー。基本的に起こりえないと思われる
                ErrorStatus = GetLastError();
                break;
            }

            // USBデバイス情報の詳細を取得
            DevInfoData.cbSize = sizeof( SP_DEVINFO_DATA );
            SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData);

            // 詳細情報のデータを取得
            SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, NULL, 0, &RegSize );
            PropertyValueBuffer = (BYTE*) malloc( RegSize * sizeof(BYTE) );
            SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, PropertyValueBuffer, RegSize, NULL );

            CharUpper( (PTCHAR)PropertyValueBuffer );

            _tprintf( TEXT("Hardware ID : [%s]\n"), PropertyValueBuffer );

    #if !NICO_CHAN_TEST
            // BUFFALO Device
            if( (_tcsstr( (PTCHAR)PropertyValueBuffer, TEXT("VID_0411&PID_0") ) != NULL) ||
                (_tcsstr( (PTCHAR)PropertyValueBuffer, TEXT("VID_0411&PID_1") ) != NULL) )
    #else
            CharUpper( (PTCHAR)tstrHardwareID );
            if( (_tcsstr( (PTCHAR)PropertyValueBuffer, tstrHardwareID ) != NULL) )
    #endif NICO_CHAN_TEST
            {
                DEVINST     devInstChild;
                TCHAR       pszDevInstanceId[MAX_PATH];
                ULONG       ulSize;
                LPTSTR      pszList;

                // ここからはドライブレターとのマッチングで使用する情報を取得する

                // VID/PIDが一致した DEVINSTを使用して
                // "DiskDrive" デバイス クラスの Device Instance Handleを取得する

                dwRet = CM_Get_Child( &devInstChild, DevInfoData.DevInst, 0 );
                if( dwRet != CR_SUCCESS )
                {
                    _tprintf( TEXT("CM_Get_Child() Err.[%d][%d]\n"), dwRet, GetLastError() );
                    goto EndLabel;
                }

    LOOP_LABEL:

                dwRet = CM_Get_Device_ID( devInstChild, pszDevInstanceId, MAX_PATH, 0 );
                if( dwRet != CR_SUCCESS )
                {
                    _tprintf( TEXT("CM_Get_Device_ID() Err.[%d][%d]\n"), dwRet, GetLastError() );
                    goto EndLabel;
                }
                _tprintf( TEXT("Device Instance ID : [%s]\n"), pszDevInstanceId );


                // Instance Pathを取得する

                dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&VolumeClassGuid, pszDevInstanceId, 0 );
                if( dwRet != CR_SUCCESS )
                {
                    _tprintf( TEXT("CM_Get_Device_Interface_List_Size() Err.[%d][%d]\n"), dwRet, GetLastError() );
                    goto EndLabel;
                }
                _tprintf( TEXT("CM_Get_Device_Interface_List_Size[%d]\n"), ulSize );


                RegSize = (ulSize * sizeof(TCHAR)) +1; // +1:GetVolumeNameForVolumeMountPoint()で 最後に '\'が必要なため
                pszList = (LPTSTR) malloc( RegSize );

                if( pszList == NULL )
                {
                    _tprintf( TEXT("malloc() Err.[%d][%d]\n"), RegSize, GetLastError() );
                    goto EndLabel;
                }

                dwRet = CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pszDevInstanceId, pszList, ulSize, 0 );

                if( dwRet != CR_SUCCESS )
                {
                    _tprintf( TEXT("CM_Get_Device_Interface_List() Err.[%d][%d]\n"), dwRet, GetLastError() );
                    free(pszList);
                    goto EndLabel;
                }
                _tprintf( TEXT("Instance Path : [%s]\n"), pszList );


    #if 1
    // ====>
                if ( *pszList == NULL )
                {
                    ULONG   ulDeviceIDsListSize       = 0;
                    ULONG   ulDeviceInterfaceListSize = 0;
                    PTCHAR  pDeviceIDsList            = NULL;
                    PTCHAR  pDeviceInterfacesList     = NULL;

                    if( CM_Get_Device_ID_List_Size( &ulDeviceIDsListSize, pszDevInstanceId, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
                    {
                        ulDeviceIDsListSize *= sizeof(TCHAR);
                        pDeviceIDsList = (PTCHAR)malloc( ulDeviceIDsListSize );

                        if ( pDeviceIDsList )
                        {
                            if( CM_Get_Device_ID_List( pszDevInstanceId, pDeviceIDsList, ulDeviceIDsListSize, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
                            {
                                if ( CM_Get_Device_Interface_List_Size( &ulDeviceInterfaceListSize, (LPGUID)&VolumeClassGuid, pDeviceIDsList, 0 ) == CR_SUCCESS )
                                {
                                    ulDeviceInterfaceListSize *= sizeof(TCHAR);
                                    pDeviceInterfacesList = (PTCHAR)malloc( ulDeviceInterfaceListSize );
                                    if ( pDeviceInterfacesList )
                                    {
                                        if ( CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pDeviceIDsList, pDeviceInterfacesList, ulDeviceInterfaceListSize, 0 ) == CR_SUCCESS )
                                        {
                                            free(pszList);
                                            pszList = NULL;
                                            RegSize = 0;

                                            RegSize = ulDeviceInterfaceListSize + sizeof( TCHAR );
                                            pszList = (PTCHAR)malloc( RegSize );
                                            ZeroMemory( pszList, RegSize );
                                            CopyMemory( pszList, pDeviceInterfacesList, ulDeviceInterfaceListSize);
                                        }
                                        free( pDeviceInterfacesList );
                                    }
                                }
                            }
                            free( pDeviceIDsList );
                        }
                    }
                }
    // <====
    #endif


                ulSize = _tcslen( pszList );
                pszList[ulSize] = '\\';
                pszList[ulSize+1] = NULL;
                _tprintf( TEXT("Instance Path2[%d] : [%s]\n"), ulSize, pszList );

                dwRet = GetVolumeNameForVolumeMountPoint( pszList, pszVolumeName, MAX_PATH );
                if( dwRet == 0 )
                {
                    _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
                    free(pszList);
                    goto EndLabel;
                }

                _tprintf( TEXT("VolumeName : [%s]\n"), pszVolumeName );

                if ( !(_tcsnicmp( pszVolumeName, pszTargetVolumeName, _tcslen(pszTargetVolumeName) )) )
                {
                    _tprintf( TEXT("!!! Note !!!\n") );
                    _tprintf( TEXT("\tHardware ID        : [%s]\n"), PropertyValueBuffer );
                    _tprintf( TEXT("\tSymbolic Link Name : [%s]\n"), pszList );
                    _tprintf( TEXT("\tVolumeName         : [%s]\n"), pszVolumeName );
                    _tprintf( TEXT("!!!! Target volume devie is found !!!!\n") );
                    MatchFound = true;
                }
                else
                {
                    DEVINST     SiblingDevInst;

                    if ( CM_Get_Sibling( &SiblingDevInst, devInstChild, 0 ) == CR_SUCCESS )
                    {
                        devInstChild = SiblingDevInst;
                        goto LOOP_LABEL;
                    }
                }

                free(pszList);
            }

    EndLabel:
            free(PropertyValueBuffer);
            InterfaceIndex++;

        }//while(MatchFound)

        SetupDiDestroyDeviceInfoList( DeviceInfoTable );

        return 0;
    }
    ------------------------------------------------------------------------------

    先にご提示いただいた実行結果を見て疑問に思ったのですが...
    なぜ PID を全部指定しないのでしょうか?

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:39
    2010年5月7日 14:03

すべての返信

  • まず、始めに断っておきますが、きちんと最後まで確認していません。
    できるかもしれないと思ったことを書いていますので、もしかしたらできないかもしれませんし、無駄な手順があるかもしれません。

    1. ドライブ文字からデバイスインスタンスハンドルを得る。
    2. デバイスインスタンスハンドルからデバイスの情報を得る。

    1 は USB ドライブの安全な取り外しのサンプルなどで手に入りそうです。
    2 はできそうな気がするというだけで、具体的なサンプルを提示できる状態ではありません。
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    • 回答の候補に設定 高橋 春樹 2010年2月22日 2:01
    • 回答としてマーク 高橋 春樹 2010年2月22日 2:03
    • 回答としてマークされていない TDM850 4TX 2010年3月18日 9:47
    • 回答の候補の設定解除 TDM850 4TX 2010年3月18日 9:47
    2010年2月4日 14:05
    モデレータ
  • Azuleanさん、レス、ありがとうございます。

    処理フローを考えるゼロからのスタートでは無く、
    3日前から試行錯誤を繰り返していましたが、実現に至ってません。
    DDKの USBViewや、WEB検索で見つけたコードを参考にしてました。

    現時点での、ポイント質問用にコードを掲載させて頂きます。

    このコードでは、ドライブを開くことができてません。
    CreateFileで失敗しています。

    QueryDosDeviceを使用せず、CreateFile の lpFileName を、ドライブレター(”\\.\E:”など)としていると成功しますが、
    続くデバイス情報が、大量にヒットしてしまいます。


    コード最初の static 定義は、
    DDKへのパス(\WinDDK\6001.18001\inc\api)を設定し、usbiodef.h をインクルードしていても、
    GUID_DEVINTERFACE_USB_HOST_CONTROLLER や GUID_DEVINTERFACE_USB_DEVICE で
    リンクエラーとなってしまうため、直設定で行っています。

    #include "stdafx.h"
    
    #include <windows.h>
    #include <setupapi.h>
    
    #pragma comment( lib, "setupapi.lib" )
    
    
    static /*const*/ GUID GUID_DEVINTERFACE_USB_DEVICE = 
    { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
    
    static /*const*/ GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = 
    { 0x3abf6f2d, 0x71c4, 0x462a, { 0x8a, 0x92, 0x1e, 0x68, 0x61, 0xe6, 0xaf, 0x27 } };
    
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int i;
    
    	// ドライブレターの取得
    	DWORD	dwDrives = GetLogicalDrives();
    	TCHAR	pszDrives[MAX_PATH];
    	int		nIndex = 0;
    	TCHAR	cbDrive = _T('A');
    
    	ZeroMemory( pszDrives, sizeof(TCHAR) * MAX_PATH);
    
    	for(i = 0; i <= 'Z' - 'A'; i++)
    	{
    		if( !((1 << i) & dwDrives) )
    			continue;
    		pszDrives[nIndex++] = cbDrive + i;
    	}
    
    	//ドライブごとに処理
    	int nSize = (int)_tcslen( pszDrives );
    	for( i=1; i < nSize; i++ )
    	{
    		DWORD	dwRet;
    		TCHAR	strDrive[8];
    		TCHAR	pszTargetPath[MAX_PATH];
    
    		sprintf_s( strDrive, sizeof(strDrive), "%c:\\", pszDrives[i] );
    		UINT drvType = GetDriveType( strDrive );
    		if( drvType == DRIVE_REMOVABLE )
    		{ // リムーバブルのみ
    			strDrive[2] = NULL;
    			dwRet = QueryDosDevice( strDrive, pszTargetPath, MAX_PATH );
    			if(dwRet == 0)
    				continue;
    
    			HANDLE hDrv = CreateFile( pszTargetPath,
    								GENERIC_READ | GENERIC_WRITE,
    								FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    								NULL, OPEN_EXISTING, 0, NULL );
    			if( hDrv != INVALID_HANDLE_VALUE )
    			{
    				HDEVINFO hDevInfo = SetupDiGetClassDevs( (GUID*)&GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, (HWND)hDrv, (DIGCF_PRESENT|DIGCF_ALLCLASSES));
    				if (hDevInfo != INVALID_HANDLE_VALUE)
    				{ // デバイス情報セットの取得成功
    					SP_DEVINFO_DATA		DevInfoData;
    					CHAR	szDevId[MAX_PATH];
    					DWORD	buffersize = 0;
    
    					DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    					for( int iIdx=0 ;; iIdx++ )
    					{
    						BOOL bRet = SetupDiEnumDeviceInfo( hDevInfo, iIdx, &DevInfoData);
    						if( bRet )
    						{
    							bRet = SetupDiGetDeviceInstanceId( hDevInfo, &DevInfoData, (PSTR)szDevId, MAX_PATH, NULL);
    							if( bRet )
    							{
    								printf( "DeveiceID[%s]\n", szDevId );
    							}
    						}
    					}
    				}
    			}
    			CloseHandle( hDrv );
    		}
    	}
    
    
    	return 0;
    }
    
    
    • 回答の候補に設定 お馬鹿 2010年3月23日 9:19
    2010年2月5日 3:06
  • 既に解決されているかもしれませんが。。。。

    私も以前に同じことを考えて、実際に出来ました。
    参考にしたのは、TDM850 4TXさんと同じく、WDK に同梱されている USBView です。

    使用する API は、Win32 API, Setup API, Configuration API と多岐にわたり、かなり面倒でした。
    一番の問題は、Drive Letter と、それに対応する USB Storage Device の関連をどのように取得するか、という点でした。

    Drive Letter はあくまでも User Mode 側の概念的な話なので、USBStor などの USB デバイス ドライバ側は、
    その USB Storage Device に割り当てられた Drive Letter を関知していません。
    なので、独自にその関係を割り出す処理が必要となります。

    私のとった実装の概要は、以下の通りです。

    1.  GetLogicalDriveString() / QueryDosDevice() / GetVolumeNameForVolumeMountPoint() API を組み合わせ、
         現在割り当てられている Drive Letter に対応する Volume Name を取得する。

    2. Setup API で、GUID_CLASS_USB_DEVICE の Device Information Set を取得し、GM_Get_DevNode_Status() で
        DN_REMOVABLE 属性を持つデバイスのみの Device Instance を抽出し、その Child Device に対して CM_Get_Device_ID(),
        CM_Get_Device_Interface_List() などの複数の Configuration API を駆使して、その Storage Device に対応する Instance Path を取得します。

    3. 上記 2 で Instance Path が取得出来たら、そのPath Name で GetVolumeNameForVolumeMountPoint() コールを行い、
        上記 1で取得した Volume Name と一致するモノを探します。
        つまり、Voluem Name が一致するものが、その USB Storage Device に対応する Drive Letter になるわけです。

    (残念ながら、上記1~3までの処理に関しては、WDK にサンプルはありません。)

    上記3で取得した Instance Path には、VID と PID の文字列が含まれているので、 そこから取得することもできますが、
    ちゃんと Device Descriptor から VID / PID を取得したいのであれば、さらにその Device Instance から対応する Hub Device の
    Device Instance を特定し、その Hub Device Instance から Instance Path を取得して、最終的に
    IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION で Device Descriptor の情報を取得する必要があります。
    この部分に関しては、USBView での実装が非常に参考になると思います。

    上記は、ホントに概要です。
    また、USB メモリ、USB CD-ROM、USB HDD, USB Floppy など Device Class に依存して、微妙に取得方法が変わってきますので、
    その点も考慮する必要があります。

    個人的にはかなり面倒だった記憶があり、ここでは書ききれません...
    少なくとも、上記に示されている単純なコードだけでは無理です。
    基本的な考え方は間違っていませんが、ポイントは USB Storage Device の Child Device として接続されている DevNode をチェックして
    行かないと、Drive Letter との関連は取得できないということです。
    つまり、GUID_CLASS_USB_DEVICE で列挙される Device Instnce は、あくまでも USB Device に対する Instance であり、
    Drive Letter との関連はsの Child Device である Volume クラスなどの DevNode で管理されている...ということだと思います。




    • 回答としてマーク 高橋 春樹 2010年2月22日 2:02
    • 回答としてマークされていない TDM850 4TX 2010年3月18日 9:48
    • 回答としてマーク TDM850 4TX 2010年5月15日 12:42
    2010年2月10日 8:28
  • かびるんるんさん、レス、ありがとうございます。

    試行錯誤を繰り返していますが、未だ解決できていません。
    頂いた内容で、質問があります。

    ● 手順1について
    記載から考えると、QueryDosDevice()で取得したパスを
    GetVolumeNameForVolumeMountPoint() で使用するように思えるのですが、
    エラーとなってしまいます。
    GetVolumeNameForVolumeMountPoint() のMSDN説明を読み、
    ディレクトリのような最終に "\0"となるようにしていますが、エラーとなります。

    (例えば)"F:\"で取得したパスは使えるのでしょうか?


    ● 手順2について
    Instance Path とは、具体的には何の関数を使用しておられますでしょうか?
    CM_Get_Device_Interface_List() の戻りが NULLになってしまうのは、
    CM_Get_Device_ID()で Child Device が選びきれていないという事になりますでしょうか?

    2010年2月15日 7:52
  • おしいところまで来ていると思うのですが、VID/PIDとの関連付けができませんでした。

    現時点での調査ソースを掲載いたします。

    if0 部分の GetVolumeNameForVolumeMountPoint() では、APIの形式と違うので失敗します。
    ここが疑問点であります。

    if0 else 部分のは、CM_Get_Device_ID() で VID/PIDが含まれている DevInfoData.DevInst が見受けられますが、
    DevInst 検索で引っかかった IDでは無いです。


    VS2005 C++で Win32コンソールアプリアプリケーションです。

    #include "stdafx.h"
    
    #include <windows.h>
    #include <setupapi.h>	// SetupDixxx
    #include <Cfgmgr32.h>	// CM_Get_xxx
    #include <rpc.h>		// GUI変換
    
    #pragma comment( lib, "setupapi.lib" )
    #pragma comment( lib, "Cfgmgr32.lib" )
    #pragma comment( lib, "rpcrt4.lib" )
    
    
    static /*const*/ GUID GUID_DEVINTERFACE_USB_DEVICE = 
    { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
    
    LPTSTR ErrorMsg(DWORD ErrorNum);
    BOOL GetDevNodeRegistryProperty( DEVINST devInst, ULONG nProperty, TCHAR* pstrText);
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int		i;
    	BOOL	bRet;
    	DWORD	dwRet;
    	TCHAR	strDrive[8];
    	TCHAR	pszPhysicalDeviceName[MAX_PATH];
    	TCHAR	pszVolumeName[MAX_PATH];
    	TCHAR	pszPropertyName[MAX_PATH];
    
    /* ●1 ドライブから物理名とボリューム名を取得 */
    	// ドライブレターの取得
    	DWORD	dwDrives = GetLogicalDrives();
    	TCHAR	pszDrives[MAX_PATH];
    	int		nIndex = 0;
    	TCHAR	cbDrive = _T('A');
    
    	ZeroMemory( pszDrives, sizeof(TCHAR) * MAX_PATH);
    
    	for(i = 0; i <= 'Z' - 'A'; i++)
    	{
    		if( !((1 << i) & dwDrives) )
    			continue;
    		pszDrives[nIndex++] = cbDrive + i;
    	}
    
    	//ドライブごとに処理
    	int nSize = (int)_tcslen( pszDrives );
    	for( i=1; i < nSize; i++ )
    	{ // ドライブレター毎のループ
    		sprintf_s( strDrive, sizeof(strDrive), "%c:\\", pszDrives[i] );
    		printf("Note:Drive[%s] is ", strDrive );
    
    		UINT drvType = GetDriveType( strDrive );
    		if( drvType == DRIVE_REMOVABLE )
    		{ // リムーバブルのみ
    			printf("REMOVABLE\n", strDrive );
    
    			// 物理名を取得
    			strDrive[2] = NULL;
    			dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
    			if(dwRet == 0)
    			{
    				dwRet = GetLastError();
    				printf( "QueryDosDevice() Error! [%d]\n", dwRet );
    				printf( "--> %s\n", ErrorMsg(dwRet) );
    				return 1;
    			}
    			printf("PhysicalDeviceName[%s]\n", pszPhysicalDeviceName );
    
    			// ボリューム名を取得
    			strDrive[2] = '\\';
    			dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszVolumeName, MAX_PATH );
    			if( dwRet == 0 )
    			{
    				dwRet = GetLastError();
    				printf( "GetVolumeNameForVolumeMountPoint() Error! [%d]\n", dwRet );
    				printf( "--> %s\n", ErrorMsg(dwRet) );
    				return 1;
    			}
    			printf("VolumeName[%s]\n", pszVolumeName );
    		}
    		else
    		{
    			printf("Not REMOVABLE\n", strDrive );
    		} // if( drvType == DRIVE_REMOVABLE ) 終端
    	} // ドライブレター毎のループ 終端
    
    
      /* ●2 Device Instance を取得 */
    	DEVINST     devInst;
    	DEVINST     devInstNext;
    	CONFIGRET   cr;
    
    	cr = CM_Locate_DevNode( &devInst, NULL, 0 );
    	if( cr != CR_SUCCESS )
    	{
    		dwRet = GetLastError();
    		printf( "CM_Locate_DevNode() Error! cr[%d] err[%d]\n", cr, dwRet );
    		printf( "--> %s\n", ErrorMsg(dwRet) );
    		return 1;
    	}
    
    	while(1)
    	{ // DevInst 検索ループ
    		//printf( "Device Instance[%d]\n", devInst);
    		bRet = GetDevNodeRegistryProperty( devInst, CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME, pszPropertyName );
    		if( (bRet==FALSE) || (0 != (strcmp(pszPhysicalDeviceName, pszPropertyName))) )
    		{
    			cr = CM_Get_Child(&devInstNext,devInst,0);
    			if(cr == CR_SUCCESS)
    			{
    				devInst = devInstNext;
    				continue;
    			}
    
    			while(1)
    			{
    				cr = CM_Get_Sibling(&devInstNext,devInst,0); // 次の兄弟ノードハンドルを取得
    				if(cr == CR_SUCCESS)
    				{
    					devInst = devInstNext;
    					break;
    				}
    
    				cr = CM_Get_Parent(&devInstNext,devInst,0);	// 兄弟で無ければ親に戻す
    				if(cr != CR_SUCCESS)
    				{
    					dwRet = GetLastError();
    					printf( "CM_Get_Parent() Error! cr[%d] err[%d]\n", cr, dwRet );
    					printf( "--> %s\n", ErrorMsg(dwRet) );
    					return 1;
    				}
    
    				devInst = devInstNext;
    			}
    			continue;
    		}
    		else
    		{
    			//デバイス検出成功
    			printf("Device found. DevInst[%d] Name[%s]\n", devInst, pszPropertyName);
    			break;
    		}
    	} // DevInst 検索ループ 終端
    
    
    
    
      /* ●3 同じ Device Instance を取得し、VID/PIDを取得する */
    	HDEVINFO hDevInfo = SetupDiGetClassDevs( NULL, NULL, NULL, (DIGCF_PRESENT|DIGCF_ALLCLASSES) );
    	if (hDevInfo != INVALID_HANDLE_VALUE)
    	{ // デバイス情報セットの取得成功
    		SP_DEVINFO_DATA				DevInfoData;
    		DWORD	buffersize = 0;
    
    		DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    		for( int i=0 ;; i++ )
    		{
    			bRet = SetupDiEnumDeviceInfo( hDevInfo, i, &DevInfoData);
    			if( !bRet )
    			{
    				dwRet = GetLastError();
    				printf( "SetupDiEnumDeviceInfo() Error! [%d]\n", dwRet );
    				printf( "--> %s\n", ErrorMsg(dwRet) );
    				SetupDiDestroyDeviceInfoList(hDevInfo);
    				return 1;
    			}
    
    #if 0
    			if( devInst == DevInfoData.DevInst )
    			{
    				TCHAR	pszDevInstanceId[MAX_PATH];
    				cr = CM_Get_Device_ID( DevInfoData.DevInst, pszDevInstanceId, MAX_PATH, 0 );
    				if( cr == CR_SUCCESS )
    				{
    					printf("DevInstanceId  DevInst[%d] [%s]\n", DevInfoData.DevInst, pszDevInstanceId);
    
    					TCHAR	pszVolumeName2[MAX_PATH];
    					dwRet = GetVolumeNameForVolumeMountPoint( pszDevInstanceId, pszVolumeName2, MAX_PATH );
    					if( dwRet == 0 )
    					{
    						dwRet = GetLastError();
    						printf( "GetVolumeNameForVolumeMountPoint(2) Error! [%d]\n", dwRet );
    						printf( "--> %s\n", ErrorMsg(dwRet) );
    						return 1;
    					}
    					printf("VolumeName2[%s]\n", pszVolumeName2 );
    					break;
    				}
    				else
    				{
    					dwRet = GetLastError();
    					printf( "CM_Get_Device_ID() Error! cr[%d] err[%d]\n", cr, dwRet );
    					printf( "--> %s\n", ErrorMsg(dwRet) );
    					SetupDiDestroyDeviceInfoList(hDevInfo);
    					return 1;
    				}
    			}
    #else
    			// デバイスのステータスを取得
    			ULONG status  = 0;
    			ULONG problem = 0;
    			CONFIGRET cr = CM_Get_DevNode_Status( &status, &problem, DevInfoData.DevInst, 0);
    			if( cr != CR_SUCCESS )
    			{
    				dwRet = GetLastError();
    				printf( "CM_Get_DevNode_Status() Error! cr[%d] err[%d]\n", cr, dwRet );
    				printf( "--> %s\n", ErrorMsg(dwRet) );
    				SetupDiDestroyDeviceInfoList(hDevInfo);
    				return 1;
    			}
    
    			if( status & DN_REMOVABLE )
    			{
    				TCHAR	pszDevInstanceId[MAX_PATH];
    				cr = CM_Get_Device_ID( DevInfoData.DevInst, pszDevInstanceId, MAX_PATH, 0 );
    				if( cr == CR_SUCCESS )
    				{
    					printf("DevInstanceId  DevInst[%d] [%s]\n", DevInfoData.DevInst, pszDevInstanceId);
    				}
    				else
    				{
    					dwRet = GetLastError();
    					printf( "CM_Get_Device_ID() Error! cr[%d] err[%d]\n", cr, dwRet );
    					printf( "--> %s\n", ErrorMsg(dwRet) );
    					SetupDiDestroyDeviceInfoList(hDevInfo);
    					return 1;
    				}
    			}
    #endif // if0
    
    		}
    		SetupDiDestroyDeviceInfoList(hDevInfo);
    
    	}
    	else
    	{
    		dwRet = GetLastError();
    		printf( "SetupDiGetClassDevs() Error! [%d]\n", dwRet );
    		printf( "--> %s\n", ErrorMsg(dwRet) );
    		SetupDiDestroyDeviceInfoList(hDevInfo);
    		return 1;
    	}
    
    
    	return 0;
    }
    
    LPTSTR ErrorMsg(DWORD ErrorNum)
    {
    	LPVOID	lpMsgBuf; 
    
    	FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    				   FORMAT_MESSAGE_FROM_SYSTEM | 
    				   FORMAT_MESSAGE_IGNORE_INSERTS |
    				   FORMAT_MESSAGE_MAX_WIDTH_MASK, 
    				   NULL, 
    				   ErrorNum, 
    				   MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), 
    				   (LPTSTR) &lpMsgBuf, 
    				   0, 
    				   NULL 
    				  );
    
    	return((LPTSTR)lpMsgBuf);
    }
    
    //
    //	DEVINSTのプロパティ文字列取得
    //
    //CM_Get_DevNode_Registry_Propertyにより文字列データを取得する
    //
    BOOL GetDevNodeRegistryProperty( DEVINST devInst, ULONG nProperty, TCHAR* pstrText)
    {
    	ULONG		nDataSize = 0;
    	CONFIGRET	cr;
    	DWORD		dwRet;
    
    	if( pstrText == NULL )
    	{
    		return	FALSE;
    	}
    
    	// バッファサイズを調べる
    	cr = CM_Get_DevNode_Registry_Property( devInst, nProperty, NULL, NULL, &nDataSize, 0 );
    	//if(cr != CR_SUCCESS)
    	//{
    	//	dwRet = GetLastError();
    	//	printf( "CM_Get_DevNode_Registry_Property1() Error! cr[%d] err[%d]\n", cr, dwRet );
    	//	printf( "--> %s\n", ErrorMsg(dwRet) );
    	//	return	FALSE;
    	//}
    
    	// プロパティ文字列取得
    	cr = CM_Get_DevNode_Registry_Property( devInst, nProperty, NULL, pstrText, &nDataSize, 0 );
    	if( (cr!=CR_SUCCESS) && (cr!=CR_BUFFER_SMALL) )
    	{
    		dwRet = GetLastError();
    		printf( "CM_Get_DevNode_Registry_Property2() Error! cr[%d] len[%d] err[%d]\n", cr, nDataSize, dwRet );
    		printf( "--> %s\n", ErrorMsg(dwRet) );
    		return	FALSE;
    	}
    
    	return	TRUE;
    }
    
    2010年2月15日 10:51
  • TDM850 4TX さん、こんにちは。
    レスが遅くなってしまい申し訳ありません。

    ご質問の件につきまして、気がついたことを書いておきます。

    ☆ GetVolumeNameForVolumeMountPoint() について
    Source Code を見る限り、この関数の使い方は間違っていないと思いますが、1st パラメータの Volume Mount Point を
    示す文字列が null-terminated していないように見受けられます。
    MSDN のドキュメントには、null-terminated でないとダメ...とは書いてありませんが、NULL 終端の文字列でないとダメだったと思います。

    ☆ Instance Path について
    私の表現がちょっとおかしかったのかもしれませんね。
    私がここで言った Instance Path とは、VolumeClassGuid を指定して CM_Get_Device_Interface_List() をコールした
    際に取得される、 Interface Instance のことです。
    この CM_Get_Device_Interface_List() コールで取得された Interface Instance を  Volume Mount Point の Path として
    GetVolumeNameForVolumeMountPoint() をコールし、その結果取得される Volume Name を手順1で予め取得した Volume Name
    と比較し、一致するのが対応するドライブ レターと言うことです。
    CM_Get_Device_Interface_List() でエラーになるとのことですが、私の書いたコードと非常に良く似ているのですが、
    細かいところで若干異なっているので、理由はわかりません。
    ただ、CM_Get_Device_Interface_List() コールの際に指定する GUID や Device Instance ID が適切でないと、
    当然目的とする Interface Instance も取得されません。

    • 回答としてマーク 高橋 春樹 2010年2月22日 2:02
    • 回答としてマークされていない TDM850 4TX 2010年3月18日 9:47
    • 回答としてマーク TDM850 4TX 2010年3月18日 10:43
    • 回答としてマークされていない TDM850 4TX 2010年3月19日 8:30
    • 回答としてマーク TDM850 4TX 2010年5月15日 12:42
    2010年2月17日 1:28
  • かびるんるんさん、こんにちは。
    お世話になっております。ご回答ありがとうございます。

    重ねて質問となり、済みません。

    ● GetVolumeNameForVolumeMountPoint() について
    下名の説明がおかしかったようです。
    NULL 終端の文字列として渡してみたのですが、エラーとなっていました。

    ドライブレター("F:\")からは、
    "\Device\Harddisk1\DP(1)0-0+4" というような文字列を取得していますが、
    これは見当違いの値となりますでしょうか?

    CM_Get_Device_ID()から取得した値を見れていないので、違いが分かっていません。


    ● GUIDについて
    現状、GUID_DEVINTERFACE_USB_DEVICE で検索を行っています。
    GUID_DEVINTERFACE_USB_HOST_CONTROLLER でも行ってみます。

    2010年2月18日 3:12
  • TDM850 4TX さん、こんにちは。

    私の説明が少しおかしかったようですね。。。申し訳ありません。

    今回、F: ドライブに対して "\Device\Harddisk1\DP(1)0-0+4" の文字列が取得されたとのことですが、
    これは QueryDosDevice() コールで 1st パラメータに "F:\0" (F:) 等の DOS デバイス名を指定した場合に、
    2nd パラメータにかえされた Symbolic Link Name でしょうか?
    (おそらく、試された環境は XP だと思いますが...
      Volume Object を管理するドライバは、XP と Vista 以降の OS では異なっており、Vista / 7 環境で
      同様に QueryDosDevice() コールを行った場合、Symbolic Link Name として取得される名前は、
      "\Device\HarddiskVolumeXX" のような名前になると思います。)

    ドライブ レター情報を基に Volume Name を取得する場合には、TDM850 4TX さんが認識されていますように、
    GetVolumeNameForVolumeMountPoint() の 1st パラメータには "F:\\\0" (F:\) ようなドライブ レターの
    NULL 終端文字列を渡します。
    そうすると、2nd パラメータにセットしたバッファには、"\\?\Volume\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
    のような名前が返されてくるはずです。
    (ネットワーク ドライブの場合は返されません。)

    先の返信で QueryDosDevvice() の使用が必要と書きましたが、私の作ったサービス プログラムでは、USB ストレージ
    デバイスに割り当てられたドライブ レターの取得以外に、別途 Device Node 等のチェックが必要だったため、
    QueryDosDevice() 等の API を使用しています。 (説明が足りず、申し訳ありませんでした。)

    GUID には、GUID_DEVINTERFACE_USB_DEVICE を使用されているとのことですが、私の場合は先にも述べましたように、
    全ての USB デバイスの Device Node チェック等の必要があったため、SetupDiGetClassDevs() API では
    GUID_CLASS_USB_DEVICE を使用していいます。

    SetupDiGetClassDevs() で獲得した Device Information Set から個々の Device Instance を取得し、
    CM_Get_Child() で Child Device Node の中に "Volume" クラスが存在しているかを確認しています。
    チェック対象の USB デバイスが USB メモリや USB HDD の場合、その Child Device Node の中には必ず
    "Volume" クラスが介在するので、その Device Node から CM_GETIDLIST_FILTER_REMOVALRELATIONS に該当する
    Device Instance ID を割り出して、そこから最終的にドライブ レターを求める訳です。

    チェック対象の USB デバイスが Floppy や CD-ROM / DVD の場合は "Volume" クラスは介在しませんので、
    ちょっと処理を変える必要がありますが、基本的な考え方は同じです。

    ちなみに、GUID_DEVINTERFACE_USB_HOST_CONTROLLER はその名前の通り Host Controller 側の話なので、
    今回の場合関係ないと思います。

    • 回答としてマーク 高橋 春樹 2010年2月22日 2:02
    • 回答としてマークされていない TDM850 4TX 2010年3月18日 9:47
    • 回答としてマーク TDM850 4TX 2010年3月18日 10:43
    • 回答としてマークされていない TDM850 4TX 2010年3月19日 8:31
    • 回答としてマーク TDM850 4TX 2010年5月15日 12:42
    2010年2月18日 7:56
  • かびるんるんさん、こんにちは。
    お世話になっております。
    早速のご回答ありがとうございます。

    済みません。下名の情報も間違っているところがありました。

    "\Device\Harddisk1\DP(1)0-0+4"
    これはご指摘の通り、QueryDosDevice() で取得した値になります。

    Volume Name は、 "F:\\\0" (F:\)で実行して、、"\\?\Volume\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
    を取得していました。

    間違った報告で、詳細な説明をいただき、済みません。


    GUID_CLASS_USB_DEVICE
    かびるんるんさんの実現できた処理に、先ずはあわせて、試行錯誤してみます。
    ありがとうございます。
    2010年2月18日 9:40
  • こんにちは。フォーラムオペレーターの高橋春樹です。

    Azuleanさん、かびるんるんさん
    アドバイスの投稿有難うございました。

    TDM850 4TXさん
    MSDNフォーラムのご利用有難うございました。

    今回、Azuleanさん、かびるんるんさんからの投稿が、有用な情報であったと思いましたので、
    一旦、回答マークを付けさせてもらいました。

    もし、試行錯誤するとのことですが、もし新たな情報がありましたらご投稿して頂きたいと思ってます。

    尚、回答マークは問題解決を意味するものではないので、その他アドバイスがありましたら
    ご投稿の程、宜しくお願いします。


    マイクロソフト株式会社 フォーラム オペレーター 高橋春樹
    2010年2月22日 2:06
  • ニコチャン大王さん、こんにちは。
    お世話になっております。

    別作業が入っていて、こちらの作業が停止していました。
    昨日より、また作業開始しているのですが、解決できていません。

    試行錯誤していて疑問になったことがあります。


    > 上記3で取得した Instance Path には、VID と PID の文字列が含まれている

    CM_Get_Device_IDで取得した文字列で、
     "USB\VID_xxxx&PID_xxxx\000000000000"
    という値を取得できるのですが、この文字列の後尾に "\0" を付加して、
    GetVolumeNameForVolumeMountPoint() を実行してもエラー(LastError:1)となります。


    > Device Node の中には必ず "Volume" クラスが介在するので

    全てのデバイスを CM_Get_Child()を使って再起コールにて検索し、
    CM_Get_Device_Interface_List() で取得した文字列は
     "\\?\STORAGE#RemovableMedia#7&847c7dd&0&RM#{GUID}\"
    となりこちらは GetVolumeNameForVolumeMountPoint() を実行してもエラーとならず、
    ドライブレターで GetVolumeNameForVolumeMountPoint() を実行した文字列と一致します。


    疑問①
    VID/PIDが入っている時の DEVINSTと、
    Volumeクラスを検出できた時の DEVINST をマッチさせる方法が分かりませんでした。


    疑問②
    USBView では、HubDeviceをハンドルとして IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX をかけていますが、
    DEVINST からハンドルを生成する方法はあるのでしょうか?



    > etupDiGetClassDevs() API では GUID_CLASS_USB_DEVICE を使用しています。

    GUID_CLASS_USB_DEVICE と GUID_DEVINTERFACE_USB_DEVICE は同じ値でした。
      http://msdn.microsoft.com/en-us/library/bb663044.aspx
    • 回答の候補に設定 お馬鹿 2010年3月23日 9:19
    2010年3月18日 10:41
  • 再びこんばんわ。

    話がややこしくなりそうなので、USB メモリに限定して返信します。

    >CM_Get_Device_IDで取得した文字列で、
    > "USB\VID_xxxx&PID_xxxx\000000000000"
    >という値を取得できるのですが、この文字列の後尾に "\0" を付加して、
    >GetVolumeNameForVolumeMountPoint() を実行してもエラー(LastError:1)となります。

    "USB\VID_xxxx&PID_xxxx\000000000000" は USB デバイスの Instance ID で、Volume Device の Instance ID ではありません。
    なので GetVolumeNameForVolumeMountPoint() のパラメータにはなりません。
    USB メモリの場合、その上に "DiskDrive" のデバイス クラスがあるはずなので、そこまで辿って行く必要があります。


    >全てのデバイスを CM_Get_Child()を使って再起コールにて検索し、
    >CM_Get_Device_Interface_List() で取得した文字列は
    > "\\?\STORAGE#RemovableMedia#7&847c7dd&0&RM#{GUID}\"
    >となりこちらは GetVolumeNameForVolumeMountPoint() を実行してもエラーとならず、
    >ドライブレターで GetVolumeNameForVolumeMountPoint() を実行した文字列と一致します。

    USB Floppy などは USBStor の上位が "DiskDrive" のデバイス クラスにならないので、CM_GetDevice_ID_List() の
    CM_GETIDLIST_FILTER_REMOVALRELATIONS からたどっていく必要があります。


    >疑問①
    >VID/PIDが入っている時の DEVINSTと、
    >Volumeクラスを検出できた時の DEVINST をマッチさせる方法が分かりませんでした。

    何度も言うようですが、そこが一番「肝」なのです。
    USB メモリの場合、"DiskDrive" デバイス クラスの Device Instance Handle (DEVINST) が取得出来たら、
    CM_Get_Device_ID() でその DiskDrive デバイスの Device Instance ID を取得します。
    これに成功すると、
    "USBSTOR\DISK&VEN_xxxx&PROD_xxxx...."
    と言う感じの Device Instance ID が CM_Get_Device_ID() の 2nd パラメータに返されます。。
    次に、CM_Get_Device_Interface_List() の 1st パラメータに VolumeClassGuid (GUID_DEVINTERFACE_VOLUME) へのポインタと、
    2nd パラメータに上記で取得した "USBSTOR\DISK&VEN_xxxx&PROD_xxxx...." で示される DiskDrive デバイスの Device Instance ID
    をそれぞれセットしてコールします。
    (この時、あらかじめ CM_Get_Device_Interface_List_Size() でバッファ サイズを取得しておく必要があります。)
    そうすると、3rd パラメータにセットしたバッファに、"\\?\Volume\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\" の Volume Name が
    返されるはずです。
    これでやっと、USB メモリ デバイスに対応する Volume Device が特定できる訳です。


    >疑問②
    >USBView では、HubDeviceをハンドルとして IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX をかけていますが、
    >DEVINST からハンドルを生成する方法はあるのでしょうか?

    何がしたいのか、質問の意味を把握しかねますが...
    例えば、"USB\VID_xxxx&PID_xxxx\000000000000" で示される USB デバイスの Instance ID に対応する Device Instance Handle から、
    それに対応する Hub Device のハンドルが欲しいのであれば、CM_Get_Parent() で Hub Device の Device Instance Handle を取得し、
    そこから CM_Get_Device_ID() で Device Instance ID 取得し、その名前で最終的に CreateFile() をすれば、取得できると思います。


    >GUID_CLASS_USB_DEVICE と GUID_DEVINTERFACE_USB_DEVICE は同じ値でした。

    TDM850 4TX さんがご指摘されている通りですね。
    大変失礼いたしました。


    ちなみに、すぐに返事を期待されてもむりですよ。
    私にも「私の仕事」があり忙しいですので。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年3月23日 9:17
  • ニコチャン大王さん、こんにちは。
    お世話になっております。
    ご回答いただき、ありがとうございます。


    > USB デバイスの Instance ID で、Volume Device の Instance ID ではありません

    取得している "\\?\STORAGE#RemovableMedia#xxxxxxxxxxxxxx#{GUID}\" が、
    デバイスに対する VolumeDeviceだと思っていました。


    説明不足があり、済みません。
    改めて当方の行いたいことを説明させて頂くと、
    行いたい事は、同じベンダーの異なる製品の識別をしたいのです。

    例えば BUFFALOであれば
    (USB.org http://www.usb.org/developers/tools/comp_dump

    "USBSTOR\DISK&VEN_xxxx&PROD_xxxx...." の形式であると、

    "VEN_BUFFALO" が取得されます。
    当方としては、"VID_0411" 形式のベンダーIDが欲しいのです。

    製品は、プロダクトIDの上位 1桁("PID_xyyy"の "x")でグループ化されており、
    下位3桁("yyy")で製品の振分けを行い、処理を別けようとしています。

    "PROD_xxxx" では製品名称で caseが多くなり、製品が増えればメンテも煩雑になりそうなので・・・

     

    >>疑問②
     (中略)
    >何がしたいのか、質問の意味を把握しかねますが...

    USBViewでは DeviceIoControl()で VID/PIDを取得していたので、
    HubDeviceのハンドルが必要だと思っていました。


    今回のご説明で、イメージ的には、
    『ドライブレター』=『"USBSTOR\DISK&VEN_xxxx&PROD_xxxx...."』=『USBデバイス』

    これにより GetVolumeNameForVolumeMountPoint()によるマッチングが出来る。
    という解釈でいます。

    "\\?\STORAGE#RemovableMedia#xxxxxxxxxxxxxx#{GUID}\"ではキーに使えないため
    取得情報が違う。


    この解釈でよければ、

    >それに対応する Hub Device のハンドルが欲しいのであれば、
    >CM_Get_Parent() で Hub Device の Device Instance Handle を取得し、
    >そこから CM_Get_Device_ID() で Device Instance ID 取得し、
    >その名前で最終的に CreateFile() をすれば、取得できると思います。

    この CreateFile()で得たハンドルで、USBViewのように DeviceIoControl()から
    VIDと PIDが取得できれば実現できそうです。

     

    >ちなみに、すぐに返事を期待されてもむりですよ。
    >私にも「私の仕事」があり忙しいですので。

    はい、承知しております。
    お忙しいところ、ご協力いただき大変感謝しております。

    MSの方が付けた返信マークを消したのは、ご多忙の間に、他の方にも見て頂きたかったからです。
    ご気分を悪くしたのであれば、失礼しました。

    2010年3月24日 9:17
  • 再びこんばんわ。
    うーん。。。ちょっとまだ理解してもらえていないよなので、気になった点をいくつか...

    > "\\?\STORAGE#RemovableMedia#xxxxxxxxxxxxxx#{GUID}\"ではキーに使えないため
    > 取得情報が違う。

    前回示した方法は、USB メモリの場合のデバイスとボリュームを関連付ける方法です。
    USB メモリ / HDD 以外のストレージ、例えば Floppy や CD-ROM / DVD などは、
    "\\?\STORAGE#RemovableMedia#xxxxxxxxxxxxxx#{GUID}\" の方からやらないと、だめです。
    少なくとも私の実装では、USB メモリ / HDD と、Floppy / CD-ROM / DVD では、
    "USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz" という USB デバイスの Device Instance ID を取得
    するところまでは一緒ですが、そこからドライブ レターとの関連付け情報を取得するところが異なります。
    まずは、USB メモリ / HDD など、USBSTOR の上位が DiskDrive クラスになるデバイスに特化して
    実装をすることをお勧めします。
    (それが出来れば、Floppy / CD-ROM / DVD などの場合にどう実装すれば良いのかわかりやすくなるので。)

    >"VEN_BUFFALO" が取得されます。
    >当方としては、"VID_0411" 形式のベンダーIDが欲しいのです。

    とても大雑把ですが....
    例えば今、"USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz" という USB デバイスの Device Instance ID が取得できたとします。
    この USB デバイスが USB メモリ / HDD である場合、その上位のデバイス クラスは "DiskDrive" になります。
    なので、"USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz" に対応する Device Instance Handle (DEVINST) をパラメータに
    CM_Get_Child() をコールして、USB デバイスの上位のデバイス クラス (要するに Child Device) の DEVINST を取得
    します。

    -------------------------------
    1. USB デバイスの Device Instance ID ("USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz") に対応する DEVINST で
       CM_Get_Child() コールを行い、Child Device の DEVINST を取得。
    -------------------------------

    取得出来たら、それが "DiskDrive" かどうかを確認した方が良いかもしれません。
    (以降の処理でエラーになったら 「USB メモリ / HDD ではない」と判別出来ればいいだけなので、必須ではありません。)
    "DiskDrive" クラスかどうかの確認には、SetupDiGetDeviceRegistryProperty() などの API の使用が必要になります。
    必須ではないので、ここでは割愛します。

    次に、Child Device ("DiskDrive" クラス) の Device Instance ID を取得します。

    -------------------------------
    2. Child Device の DEVINST で CM_Get_Device_ID() をコールして Device Instance ID を取得。
    -------------------------------

    "DiskDrive" クラス の Device Instance ID の場合、"USBSTOR\DISK&VEN_xxxx&PROD_xxxx...." という
    Instance ID が取得出来るはずです。
    後は、前回書いた下記の処理を行えば、、
    "\\?\Volume\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
    という Volume Name が取得出来るはずです。
    (取得できなかったら、その Child Device は "DiskDrive" クラスではないので、USB メモリ / HDD ではない...ということです。)

    -------------------------------
    >CM_Get_Device_Interface_List() の 1st パラメータに VolumeClassGuid (GUID_DEVINTERFACE_VOLUME) へのポインタと、
    >2nd パラメータに上記で取得した "USBSTOR\DISK&VEN_xxxx&PROD_xxxx...." で示される DiskDrive デバイスの Device Instance ID
    >をそれぞれセットしてコールします。
    -------------------------------

    > USBViewでは DeviceIoControl()で VID/PIDを取得していたので、
    > HubDeviceのハンドルが必要だと思っていました。

    ちゃんと USB デバイスの Device Descriptor から Vender ID / Product ID / Serial Number を取得したい
    のであれば、TDM850 4TX さんが認識されているように、HubDevice のハンドルが必須になります。
    ちなみに、USB デバイスの Device Instance ID である "USB\VID_xxxx&PID_yyyy\zzzzzzzzzzzz" は、

    xxxx : Vendor ID
    yyyy : Product ID
    zzzzzzzzzzzz : Serial Number

    になってたはずです。
    ただし、Serial Number をサポートしないデバイス、あるいは Windows 側のレジストリ設定で Serial Number に
    よる識別を無効にしている場合には、"zzzzzzzzzzzz" の部分は別の文字列になります。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年3月24日 12:15
  • ニコチャン大王さん、おはようございます。
    お世話になっております。
    即日のご回答、ありがとうございます。


    下名、どうもUSBコントローラにぶら下がっている情報ツリーの認識ができていないようですね。
    もう1度、MSDNとUSBViewを読み直し、再認識してみます。

    USB デバイスの Device Instance ID から、CM_Get_Child() で探る方法を直ぐに行います。
    ありがとうございます。

    2010年3月25日 0:41
  • ニコチャン大王さん、お世話になっております。
    参照されている皆さん、こんにちは。

    まだ理解できていないためか、解決できませんでした。


    CM_Get_Device_ID()で、"USB\VID_0411&PID_0xxx&REV_0100"というような
    目的の PID/VIDが含まれている DEVINST で、

    CM_Get_Child()、CM_Get_Device_ID()と行うと、
    "USBSTOR\DISK&VEN_BUFFALO&PROD_ZZZZZZ&REV_1.00\xxxxxxxxxxxx&0"
    というような IDが取得できました。

    この IDを使用し、CM_Get_Device_Interface_List() で、
    VolumeClassGuid を指定してみたのですが、InstanceIDを取得できませんでした。

    DiskClassGuid を指定すると取得ができました。
    その時に取得できた文字列は、
    "\\?\USBSTOR#Disk&Ven_BUFFALO&Prod_XXXXXX&Rev_1.00#xxxxxxxxxxxx&0#{GUID}"
    でありました。

    最後に '\' を付加して、GetVolumeNameForVolumeMountPoint()を実行してみたのですが、
    エラーとなりました。


    VolumeClassGuid で取得できなかったのですが、
    この状況は、"DiskDrive"クラス情報を取得できていないのでしょうか?
    接続しているドライブは、マスストレージの HDDなのですが、
    CM_Get_Device_ID_List() の CM_GETIDLIST_FILTER_REMOVALRELATIONS から
    辿る必要がありますでしょうか?

    CM_Get_Device_ID_List()を "USBSTOR\DISK&VEN_BUFFALO&PROD_ZZZZZZ&REV_1.00\xxxxxxxxxxxx&0"
    で試してみましたが、SIZEを取得する事ができませんでした。

    "DiskDrive"クラスとの事でしたので DiskClassGuid を使用してみましたが、
    間違っていますでしょうか?

    当初に掲載していたソースと変わっていますので、改めて現状のソースを掲載いたします。
    VC2005 Win32コンソールアプリのプロジェクトです。
    ドライブを "E:\"を固定にしています。

    何か、勘違い、不正コードなどありましたら、ご指摘いただけると幸いです。

    #include "stdafx.h"
    #include <windows.h>
    #include <setupapi.h>	// SetupDixxx
    #include <Cfgmgr32.h>	// CM_Get_xxx
    
    #pragma comment( lib, "setupapi.lib" )
    #pragma comment( lib, "Cfgmgr32.lib" )
    
    
    static /*const*/ GUID GUID_DEVINTERFACE_USB_DEVICE = 
    { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
    
    void StrConv2Upper( char *pszStr );
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	DWORD	dwRet;
    	TCHAR	strDrive[8];
    	TCHAR	pszPhysicalDeviceName[MAX_PATH];
    	TCHAR	pszVolumeName[MAX_PATH];
    
    /* ■1 ドライブから物理名とボリューム名を取得 */
    	sprintf_s( strDrive, sizeof(strDrive), "E:\\" );
    	UINT drvType = GetDriveType( strDrive );
    	if( drvType == DRIVE_REMOVABLE )
    	{ // リムーバブルのみ
    		strDrive[2] = NULL;
    		dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
    		if(dwRet == 0)
    		{
    			printf( "QueryDosDevice() Error! [%d]\n", GetLastError() );
    			return 1;
    		}
    		printf("PhysicalDeviceName[%s]\n", pszPhysicalDeviceName );
    
    		// ボリューム名を取得
    		strDrive[2] = '\\';
    		strDrive[3] = NULL;
    		dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszVolumeName, MAX_PATH );
    		if( dwRet == 0 )
    		{
    			printf( "GetVolumeNameForVolumeMountPoint() Error! [%d]\n", GetLastError() );
    			return 1;
    		}
    		printf("Note:VolumeName[%s]\n", pszVolumeName );
    	}
    	else
    	{
    		printf("Not REMOVABLE\n", strDrive );
    		return 1;
    	}
    
    
    /* ■2 Device Instance を取得 */
    	HDEVINFO					DeviceInfoTable = INVALID_HANDLE_VALUE;
    	SP_DEVICE_INTERFACE_DATA	DevInterfaceData;
    	SP_DEVINFO_DATA				DevInfoData;
    
    	DWORD	InterfaceIndex = 0;
    	DWORD	StatusLastError = 0;
    	DWORD	RegType;
    	DWORD	RegSize;			//使いまわしあり
    	DWORD	StructureSize = 0;
    	PBYTE	PropertyValueBuffer = NULL;
    	bool	MatchFound = false;
    	DWORD	ErrorStatus;
    
    	ZeroMemory(&DevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
    	DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    
    
    	// USBデバイス用の情報セットを取得 
    	DeviceInfoTable = SetupDiGetClassDevs( &GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
    
    	while( !MatchFound )
    	{
    		DevInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
    		if( SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &GUID_DEVINTERFACE_USB_DEVICE, InterfaceIndex, &DevInterfaceData) )
    		{
    			ErrorStatus = GetLastError();
    			if( ERROR_NO_MORE_ITEMS == ErrorStatus )
    			{ //情報セットの終端
    				break;
    			}
    		}
    		else
    		{ // 予期していないエラー。基本的に起こりえないと思われる
    			ErrorStatus = GetLastError();
    			break;
    		}
    
    		// USBデバイス情報の詳細を取得
    		DevInfoData.cbSize = sizeof( SP_DEVINFO_DATA );
    		SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData);
    
    		// 詳細情報のデータを取得
    		SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, NULL, 0, &RegSize );
    		PropertyValueBuffer = (BYTE*) malloc( RegSize * sizeof(BYTE) );
    		SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, PropertyValueBuffer, RegSize, NULL );
    
    		StrConv2Upper((char*)PropertyValueBuffer);
    		printf("PropertyValueBuffer[%s]\n", PropertyValueBuffer );
    
    		if( (strstr((char*)PropertyValueBuffer, "VID_0411&PID_0") != NULL)
    			 ||
    			(strstr((char*)PropertyValueBuffer, "VID_0411&PID_1") != NULL)
    		  )
    		 { // BUFFALO Device
    			MatchFound = true;
    
    			// ここからはドライブレターとのマッチングで使用する情報を取得する
    
    			// VID/PIDが一致した DEVINSTを使用して
    			// "DiskDrive" デバイス クラスの Device Instance Handleを取得する
    			DEVINST		devInstChild;
    			dwRet = CM_Get_Child( &devInstChild, DevInfoData.DevInst, 0 );
    			if( dwRet != CR_SUCCESS )
    			{
    				printf( "CM_Get_Child() Err.[%d][%d]\n", dwRet, GetLastError() );
    				goto EndLabel;
    			}
    
    			TCHAR	pszDevInstanceId[MAX_PATH];
    			dwRet = CM_Get_Device_ID( devInstChild, pszDevInstanceId, MAX_PATH, 0 );
    			if( dwRet != CR_SUCCESS )
    			{
    				printf( "CM_Get_Device_ID() Err.[%d][%d]\n", dwRet, GetLastError() );
    				goto EndLabel;
    			}
    			printf("pszDevInstanceId[%s]\n", pszDevInstanceId );
    
    
    			// Instance Pathを取得する
    			ULONG	ulSize;
    			dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&DiskClassGuid, pszDevInstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
    			if( dwRet != CR_SUCCESS )
    			{
    				printf( "CM_Get_Device_Interface_List_Size() Err.[%d][%d]\n", dwRet, GetLastError() );
    				goto EndLabel;
    			}
    			printf("CM_Get_Device_Interface_List_Size[%d]\n", ulSize );
    
    
    			RegSize = (ulSize * sizeof(TCHAR)) +1;	// +1:GetVolumeNameForVolumeMountPoint()で 最後に '\'が必要なため
    			LPTSTR pszList = (LPTSTR) malloc( RegSize );
    			if( pszList == NULL )
    			{
    				printf( "malloc() Err.[%d][%d]\n", RegSize, GetLastError() );
    				goto EndLabel;
    			}
    
    			dwRet = CM_Get_Device_Interface_List( (LPGUID)&DiskClassGuid, pszDevInstanceId, (PCHAR)pszList, ulSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
    			if( dwRet != CR_SUCCESS )
    			{
    				printf( "CM_Get_Device_Interface_List() Err.[%d][%d]\n", dwRet, GetLastError() );
    				free(pszList);
    				goto EndLabel;
    			}
    			printf("Instance Path[%s]\n", pszList );
    
    			ulSize = (DWORD)strnlen( pszList, RegSize );
    			pszList[ulSize] = '\\';
    			pszList[ulSize+1] = NULL;
    			printf("Instance Path2[%d][%s]\n", ulSize, pszList );
    
    			dwRet = GetVolumeNameForVolumeMountPoint( pszList, pszVolumeName, MAX_PATH );
    			if( dwRet == 0 )
    			{
    				printf( "GetVolumeNameForVolumeMountPoint() Error! [%d]\n", GetLastError() );
    				free(pszList);
    				goto EndLabel;
    			}
    			printf("Note:VolumeName[%s]\n", pszVolumeName );
    			free(pszList);
    		}
    EndLabel:
    		free(PropertyValueBuffer);
    		InterfaceIndex++;
    
    	 }//while(MatchFound)	
    
    	SetupDiDestroyDeviceInfoList( DeviceInfoTable );
    
    	return 0;
    }
    
    /* 文字列中の英小文字を大文字に変換 */
    void StrConv2Upper( char *pszStr )
    {
    	char *p;
    	for (p = pszStr; *p; p++)
    		*p = toupper(*p);
    	return;
    } // StrConv2Upper
    
    2010年4月6日 6:31
  • 全く検証していませんが、以下のような感じの処理を追加すれば、うまくいくはずです。

    -----------------------------------------------------------------------
    #include "stdafx.h"
    #include <windows.h>
    #include <setupapi.h> // SetupDixxx
    #include <Cfgmgr32.h> // CM_Get_xxx

    #pragma comment( lib, "setupapi.lib" )
    #pragma comment( lib, "Cfgmgr32.lib" )


    static /*const*/ GUID GUID_DEVINTERFACE_USB_DEVICE =
    { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };

    void StrConv2Upper( char *pszStr );


    int _tmain(int argc, _TCHAR* argv[])
    {
     DWORD dwRet;
     TCHAR strDrive[8];
     TCHAR pszPhysicalDeviceName[MAX_PATH];
     TCHAR pszVolumeName[MAX_PATH];

    /* ■1 ドライブから物理名とボリューム名を取得 */
     sprintf_s( strDrive, sizeof(strDrive), "E:\\" );
     UINT drvType = GetDriveType( strDrive );
     if( drvType == DRIVE_REMOVABLE )
     { // リムーバブルのみ
      strDrive[2] = NULL;
      dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
      if(dwRet == 0)
      {
       printf( "QueryDosDevice() Error! [%d]\n", GetLastError() );
       return 1;
      }
      printf("PhysicalDeviceName[%s]\n", pszPhysicalDeviceName );

      // ボリューム名を取得
      strDrive[2] = '\\';
      strDrive[3] = NULL;
      dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszVolumeName, MAX_PATH );
      if( dwRet == 0 )
      {
       printf( "GetVolumeNameForVolumeMountPoint() Error! [%d]\n", GetLastError() );
       return 1;
      }
      printf("Note:VolumeName[%s]\n", pszVolumeName );
     }
     else
     {
      printf("Not REMOVABLE\n", strDrive );
      return 1;
     }


    /* ■2 Device Instance を取得 */
     HDEVINFO     DeviceInfoTable = INVALID_HANDLE_VALUE;
     SP_DEVICE_INTERFACE_DATA DevInterfaceData;
     SP_DEVINFO_DATA    DevInfoData;

     DWORD InterfaceIndex = 0;
     DWORD StatusLastError = 0;
     DWORD RegType;
     DWORD RegSize;   //使いまわしあり
     DWORD StructureSize = 0;
     PBYTE PropertyValueBuffer = NULL;
     bool MatchFound = false;
     DWORD ErrorStatus;

     ZeroMemory(&DevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
     DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);


     // USBデバイス用の情報セットを取得
     DeviceInfoTable = SetupDiGetClassDevs( &GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );

     while( !MatchFound )
     {
      DevInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
      if( SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &GUID_DEVINTERFACE_USB_DEVICE, InterfaceIndex, &DevInterfaceData) )
      {
       ErrorStatus = GetLastError();
       if( ERROR_NO_MORE_ITEMS == ErrorStatus )
       { //情報セットの終端
        break;
       }
      }
      else
      { // 予期していないエラー。基本的に起こりえないと思われる
       ErrorStatus = GetLastError();
       break;
      }

      // USBデバイス情報の詳細を取得
      DevInfoData.cbSize = sizeof( SP_DEVINFO_DATA );
      SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData);

      // 詳細情報のデータを取得
      SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, NULL, 0, &RegSize );
      PropertyValueBuffer = (BYTE*) malloc( RegSize * sizeof(BYTE) );
      SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, PropertyValueBuffer, RegSize, NULL );

      StrConv2Upper((char*)PropertyValueBuffer);
      printf("PropertyValueBuffer[%s]\n", PropertyValueBuffer );

      if( (strstr((char*)PropertyValueBuffer, "VID_0411&PID_0") != NULL)
        ||
       (strstr((char*)PropertyValueBuffer, "VID_0411&PID_1") != NULL)
        )
       { // BUFFALO Device
       MatchFound = true;

       // ここからはドライブレターとのマッチングで使用する情報を取得する

       // VID/PIDが一致した DEVINSTを使用して
       // "DiskDrive" デバイス クラスの Device Instance Handleを取得する
       DEVINST  devInstChild;
       dwRet = CM_Get_Child( &devInstChild, DevInfoData.DevInst, 0 );
       if( dwRet != CR_SUCCESS )
       {
        printf( "CM_Get_Child() Err.[%d][%d]\n", dwRet, GetLastError() );
        goto EndLabel;
       }

       TCHAR pszDevInstanceId[MAX_PATH];
       dwRet = CM_Get_Device_ID( devInstChild, pszDevInstanceId, MAX_PATH, 0 );
       if( dwRet != CR_SUCCESS )
       {
        printf( "CM_Get_Device_ID() Err.[%d][%d]\n", dwRet, GetLastError() );
        goto EndLabel;
       }
       printf("pszDevInstanceId[%s]\n", pszDevInstanceId );


       // Instance Pathを取得する
       ULONG ulSize;
    #if 0
       dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&DiskClassGuid, pszDevInstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
    #else
    // ====>
       dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&VolumeClassGuid, pszDevInstanceId, 0 );
    // <====
    #endif
       if( dwRet != CR_SUCCESS )
       {
        printf( "CM_Get_Device_Interface_List_Size() Err.[%d][%d]\n", dwRet, GetLastError() );
        goto EndLabel;
       }
       printf("CM_Get_Device_Interface_List_Size[%d]\n", ulSize );


       RegSize = (ulSize * sizeof(TCHAR)) +1; // +1:GetVolumeNameForVolumeMountPoint()で 最後に '\'が必要なため
       LPTSTR pszList = (LPTSTR) malloc( RegSize );
       if( pszList == NULL )
       {
        printf( "malloc() Err.[%d][%d]\n", RegSize, GetLastError() );
        goto EndLabel;
       }

    #if 0
       dwRet = CM_Get_Device_Interface_List( (LPGUID)&DiskClassGuid, pszDevInstanceId, (PCHAR)pszList, ulSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
    #else
    // ====>
       dwRet = CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pszDevInstanceId, (PCHAR)pszList, ulSize, 0 );
    // <====
    #endif
       if( dwRet != CR_SUCCESS )
       {
        printf( "CM_Get_Device_Interface_List() Err.[%d][%d]\n", dwRet, GetLastError() );
        free(pszList);
        goto EndLabel;
       }
       printf("Instance Path[%s]\n", pszList );


    #if 1
    // ====>
       if ( *pszList == NULL )
       {
        ULONG   ulDeviceIDsListSize       = 0;
        ULONG   ulDeviceInterfaceListSize = 0;
        PTCHAR  pDeviceIDsList            = NULL;
        PTCHAR  pDeviceInterfacesList     = NULL;

        if( CM_Get_Device_ID_List_Size( &ulDeviceIDsListSize, pszDevInstanceId, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
        {
         ulDeviceIDsListSize *= sizeof(TCHAR);
         pDeviceIDsList = malloc( ulDeviceIDsListSize );

         if ( pDeviceIDsList )
         {
          if( CM_Get_Device_ID_List( pszDevInstanceId, pDeviceIDsList, ulDeviceIDsListSize, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
          {
           if ( CM_Get_Device_Interface_List_Size( &ulDeviceInterfaceListSize, (LPGUID)&VolumeClassGuid, pDeviceIDsList, 0 ) == CR_SUCCESS )
           {
            ulDeviceInterfaceListSize *= sizeof(TCHAR);
            pDeviceInterfacesList = malloc( ulDeviceInterfaceListSize );
            if ( pDeviceInterfacesList )
            {
             if ( CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pDeviceIDsList, (PCHAR)pDeviceInterfacesList, ulDeviceInterfaceListSize, 0 ) == CR_SUCCESS )I
             {
              free(pszList);
              pszList = NULL;
              RegSize = 0;

              RegSize = ulDeviceInterfaceListSize + sizeof( TCHAR );
              pszList = malloc( RegSize );
                                            ZeroMemory( pszList, RegSize );
                                            CopyMemory( pszList, pDeviceInterfacesList, ulDeviceInterfaceListSize);
             }
             free( pDeviceInterfacesList );
            }
           }
          }
          free( pDeviceIDsList );
         }
        }
       }
    // <====
    #endif


       ulSize = (DWORD)strnlen( pszList, RegSize );
       pszList[ulSize] = '\\';
       pszList[ulSize+1] = NULL;
       printf("Instance Path2[%d][%s]\n", ulSize, pszList );

       dwRet = GetVolumeNameForVolumeMountPoint( pszList, pszVolumeName, MAX_PATH );
       if( dwRet == 0 )
       {
        printf( "GetVolumeNameForVolumeMountPoint() Error! [%d]\n", GetLastError() );
        free(pszList);
        goto EndLabel;
       }
       printf("Note:VolumeName[%s]\n", pszVolumeName );
       free(pszList);
      }
    EndLabel:
      free(PropertyValueBuffer);
      InterfaceIndex++;

      }//while(MatchFound) 

     SetupDiDestroyDeviceInfoList( DeviceInfoTable );

     return 0;
    }

    /* 文字列中の英小文字を大文字に変換 */
    void StrConv2Upper( char *pszStr )
    {
     char *p;
     for (p = pszStr; *p; p++)
      *p = toupper(*p);
     return;
    } // StrConv2Upper
    -----------------------------------------------------------------------

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年4月7日 4:59
  • ニコチャン大王さん、お世話になっております。
    お忙しいところ、ご回答いただき、ありがとうございます。


    早速、訂正いただいたソースをマージして試してみました。
    GetVolumeNameForVolumeMountPoint()でエラーにはならなくなったのですが、

    GetVolumeNameForVolumeMountPoint( ドライブレター ) では、
     "\\?\Volume{740609f6-7fc5-11de-be0b-005056c00008}\"

    GetVolumeNameForVolumeMountPoint( Instance Path ) では、
     "\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"

    となり、別の GUIDを取得していました。

    この GUIDで何かAPIを通せば、一致することになるのでしょうか?

    2010年4月7日 5:35
  • コマンド プロンプトで、"MountVol" を実行してみてください。

    現在のマウント ポイントとボリューム名の一覧が表示されます。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年4月7日 5:42
  • ニコチャン大王さん、お世話になっております。
    早速のご回答、ありがとうございます。


    "MountVol" を実行してみたところ、

      \\?\Volume{740609f6-7fc5-11de-be0b-005056c00008}\
        E:\

    と表示されました。
    これは、GetVolumeNameForVolumeMountPoint( ドライブレター ) と同じ値でありました。

    2010年4月7日 7:14
  • "\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"

    ↑ これはどのドライブ レターのモノでしたか?

    また、そのドライブ レターが割り当てられているデバイスは何ですか?

    おそらく E: 以外に、別の USB ストレージ デバイスが接続されているためと思われます。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年4月7日 7:28
  • ニコチャン大王さん、お世話になっております。
    早速のご回答、ありがとうございます。
    お忙しいところ、何度も済みません。

    "\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"
    ですが、

    記載ソースでは、
     GetVolumeNameForVolumeMountPoint( pszList, pszVolumeName, MAX_PATH );
    で取得し、2回目のデバッグ出力
     printf("Note:VolumeName[%s]\n", pszVolumeName );
    で表示している内容になります。

    提示しているソースに間違いが無ければ、VID/PIDで一致しているデバイスだと考えています。

    Mountvol で検出されたドライブは、Eドライブの他には、
    A(FD)、C(内蔵HDD)、D(内蔵HDD)の3つだけでした。
    USB接続しているデバイスは、対象としている Eドライブだけになります。

    何か、OSにゴミ情報が残っていたりするものでしょうか?

    2010年4月7日 8:44
  • MountVol コマンドの出力結果に、以下のマウント ポイントは出力されていないのですか?

    "\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"

    また、使用している USB デバイスの種類は何でしょうか?

    1つの USB デバイスでも、複数のインターフェイス (ボリューム等)をもつものあります。

    デバイスが1つだけだからと言って、ボリュームが1つだけとは限りません。

    とにかく、MountVol での出力結果を見ないと、なんとも言えません。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:41
    2010年4月7日 9:11
  • ニコチャン大王さん、お世話になっております。
    お早うございます。

    "\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"
    ですが、表示されていないです。

    MountVolの出力結果では次のような内容になっています。
    --------------------------------
    現在のマウント ポイントとボリューム名の考えられる値:

        \\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\
            C:\

        \\?\Volume{95a9d791-70f4-11dd-bcad-806d6172696f}\
            D:\

        \\?\Volume{95a9d792-70f4-11dd-bcad-806d6172696f}\
            A:\

        \\?\Volume{740609f6-7fc5-11de-be0b-005056c00008}\
            E:\
    --------------------------------


    > 1つの USB デバイスでも、複数のインターフェイス (ボリューム等)をもつもの

    これは内蔵メモリと SDカードでも別れますでしょうか。
    マスストレージ接続した際、SDカードを差していると、SDカードの内容もエクスプローラで参照できます。
    その場合、別のドライブで現れます。
    現状では SDカードを抜いているので、1(E)ドライブだけがエクスプローラと MountVolに出ています。

    2010年4月8日 0:51
  • >"\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"
    >ですが、表示されていないです。
    ↑ C: ドライブのボリューム名ではないのでしょうか?

    以下の処理を確認してみてはいかがでしょう?

    if ( CM_Get_Device_Interface_List_Size( &ulDeviceInterfaceListSize, (LPGUID)&VolumeClassGuid, pDeviceIDsList, 0 ) == CR_SUCCESS )
    ↑ このコールの時に pszDevInstanceId と pDeviceIDsList にセットされている文字列と、ulDeviceInterfaceListSize に返されたサイズ。

    C: ドライブは内蔵 HDD とのことなので、下側のバスは IDE/ATA もしくは AHCI なるはずだと思います。
    ですので、GUID GUID_DEVINTERFACE_USB_DEVICE を指定して C: ドライブのボリューム名が取得されるのは、
    根本的プログラムのロジックがおかしいため...と思います。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月8日 5:46
  • ニコチャン大王さん、お世話になっております。
    お忙しいところ、ご回答いただき、ありがとうございます。
    下名の返信が遅くなり、申し訳ありません。


    > C: ドライブのボリューム名ではないのでしょうか?
    はい、確かにそうです。
    Eドライブのみ注視していました。済みません。


    > このコールの時に pszDevInstanceId と pDeviceIDsList にセットされている文字列と、ulDeviceInterfaceListSize に返されたサイズ。

    ご指示いただいた場所には到達しておらず、
    直前の CM_Get_Device_ID_List()が成功していませんでした。

    if( CM_Get_Device_ID_List_Size( &ulDeviceIDsListSize, pszDevInstanceId, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )

    この部分で、サイズが取得できていませんでした。
    CR_SUCCESS で終了しているのですが、ulDeviceIDsListSize が 0 になっており、
    これにより、pszListが NULLのまま、"\" となって、Cドライブの値が取得されていたようです。


    > 根本的プログラムのロジックがおかしいため

    pszDevInstanceId には、
    "USBSTOR\DISK&VEN_BUFFALO&PROD_ZZZZZZ&REV_1.00\xxxxxxxxxxxx&0"が入っています。

    SetupDiGetClassDevs()、SetupDiEnumDeviceInterfaces() を
    GUID_DEVINTERFACE_USB_DEVICE で実行し、
    VID/PIDの内容を確認した SP_DEVINFO_DATA を使用し、
    CM_Get_Child()を実行してきた値ですが、この IDを疑ったほうが良いということでしょうか?

    2010年4月12日 1:22
  • 返信が遅くなってしまったので、既に解決してるかもしれませんが。。。

    たぶん、単純に文字列操作に問題があるんだと思います。

    少なくとも、ストレージ デバイスがUSBメモリなら、先に示した感じの実装で必ずボリューム名が取れるはずです。

    strstr() での文字列チェックの所で、ちゃんと判別できているかを再度確認するのが先決だと思います。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月15日 11:05
  • ニコチャン大王さん、お世話になっております。
    お忙しいところ、ご回答いただき、ありがとうございます。

    strstr()での値は、対象としているデバイスの内容となっていました。

    他に確認する点はありますでしょうか?

    2010年4月20日 3:40
  • とりあえず、私の環境で動作を確認したコードを以下に添付します。
    (USB メモリおよび USB フロッピーで正常に動作することを確認しています。)
    ご覧いただければご理解いただけると思いますが、このコードの基本ロジックは、
    先に示したものと全く同一です。
    変更した箇所は、以下の部分だけです。

    ☆ UNICODE 対応
    ☆ ドライブ レターおよびハードウェア ID を任意に指定できるようパラメータ処理の追加。

    先に TDM850 4TX さんが示されたコードと全く同じ条件下で実行するのであれば、以下のパラメータで実行してください。

    <ProgrameName> E: "VID_0411&PID_0"

    元々は TDM850 4TX さんが示されたコードなのであえて説明は必要ないかと思いますが、
    ドライブ レターに対応するストレージ デバイスのハードウェア ID が、プログラム実行時の 2nd パラメータと一致すると、
    以下の一文を出力するようにしてあります。

    "!!!! Target volume devie is found !!!!"

    なお、私は WDK のビルド環境を使用してビルドしましので、ヘッダー ファイルおよびライブラリ ファイルに関しては
    適宜変更してください。

    もし、仮にこれで正常に機能しない場合は、もっと別のところに問題があると思います。

     

    #define UNICODE
    #define _UNICODE
    
    #include <stdio.h>
    #include <malloc.h>
    #include <windows.h>
    #include <tchar.h>
    #include <setupapi.h> // SetupDixxx
    #include <Cfgmgr32.h> // CM_Get_xxx
    #include <initguid.h>
    #include <winioctl.h>
    #include <usbiodef.h>
    
    
    #pragma comment( lib, "setupapi.lib" )
    #pragma comment( lib, "Cfgmgr32.lib" )
    
    #define NICO_CHAN_TEST TRUE
    
    
    void Usage
    (
      PTSTR  BinaryName
    )
    {
      _tprintf( (TEXT("\n")
            TEXT("Usage:                \n")
            TEXT("   %s <drive:> <VID_xxxx&PID_xxxx> \n")
            TEXT("Ex.]                 \n")
            TEXT("   %s E: \"VID_0411&PID_0\"    \n")), BinaryName, BinaryName );
    }
    
    
    int __cdecl _tmain
    (
      int argc, 
      TCHAR* argv[]
    )
    {
      DWORD  dwRet;
      TCHAR  strDrive[8];
      TCHAR  pszPhysicalDeviceName[MAX_PATH];
      TCHAR  pszTargetVolumeName[MAX_PATH];
      TCHAR  pszVolumeName[MAX_PATH];
    
    //_asm int 3;
    
      /* ■1 ドライブから物理名とボリューム名を取得 */
    #if !NICO_CHAN_TEST
      wsprintf( strDrive, TEXT("E:\\") );
    #else
      PTSTR  tstrHardwareID;
    
      if ( argc != 3 )
      {
        Usage( argv[0] );
        return 1;
      }
      else
      {
        TCHAR  DriveLetter = argv[1][0];
    
        if ( !(( DriveLetter >= _T('a') && DriveLetter <= _T('z') ) ||
            ( DriveLetter >= _T('A') && DriveLetter <= _T('Z') )) ||
           ( argv[1][1] != _T(':')) || ( argv[1][2] != _T('\0') ) )
        {
          Usage( argv[0] );
          return 1;
        }
      }
    
      _tprintf( TEXT("Target Drive : [%s]\n"), argv[1] );
      wsprintf( strDrive, TEXT("%s\\"), argv[1] );
    
      tstrHardwareID = argv[2];
    #endif
    
      UINT drvType = GetDriveType( strDrive );
    
      if( drvType == DRIVE_REMOVABLE )
      { // リムーバブルのみ
        strDrive[2] = NULL;
        dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
        if(dwRet == 0)
        {
          _tprintf( TEXT("QueryDosDevice() Error! [%d]\n"), GetLastError() );
          return 1;
        }
    
        _tprintf( TEXT("Physical Device Name : [%s]\n"), pszPhysicalDeviceName );
    
        // ボリューム名を取得
        strDrive[2] = '\\';
        strDrive[3] = NULL;
        dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszTargetVolumeName, MAX_PATH );
    
        if( dwRet == 0 )
        {
          _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
          return 1;
        }
    
        _tprintf( TEXT("!!! Note !!!\n")
             TEXT("\tTargetVolumeName : [%s]\n\n"), pszTargetVolumeName );
      }
      else
      {
        _tprintf( TEXT("Not REMOVABLE\n"), strDrive );
        return 1;
      }
    
    
      /* ■2 Device Instance を取得 */
      HDEVINFO          DeviceInfoTable = INVALID_HANDLE_VALUE;
      SP_DEVICE_INTERFACE_DATA  DevInterfaceData;
      SP_DEVINFO_DATA       DevInfoData;
    
      DWORD  InterfaceIndex = 0;
      DWORD  StatusLastError = 0;
      DWORD  RegType;
      DWORD  RegSize;  //使いまわしあり
      DWORD  StructureSize = 0;
      PBYTE  PropertyValueBuffer = NULL;
      BOOL  MatchFound = false;
      DWORD  ErrorStatus;
    
      ZeroMemory(&DevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
      DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    
    
      // USBデバイス用の情報セットを取得 
      DeviceInfoTable = SetupDiGetClassDevs( &GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
      if ( DeviceInfoTable == INVALID_HANDLE_VALUE )
      {
        _tprintf( TEXT("DeviceInfoTable == INVALID_HANDLE_VALUE \n") );
        return 1;
      }
    
      while( !MatchFound )
      {
        DevInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
        if( SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &GUID_DEVINTERFACE_USB_DEVICE, InterfaceIndex, &DevInterfaceData) )
        {
          ErrorStatus = GetLastError();
          if( ERROR_NO_MORE_ITEMS == ErrorStatus )
          { //情報セットの終端
            break;
          }
        }
        else
        { // 予期していないエラー。基本的に起こりえないと思われる
          ErrorStatus = GetLastError();
          break;
        }
    
        // USBデバイス情報の詳細を取得
        DevInfoData.cbSize = sizeof( SP_DEVINFO_DATA );
        SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData);
    
        // 詳細情報のデータを取得
        SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, NULL, 0, &RegSize );
        PropertyValueBuffer = (BYTE*) malloc( RegSize * sizeof(BYTE) );
        SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, PropertyValueBuffer, RegSize, NULL );
    
        CharUpper( (PTCHAR)PropertyValueBuffer );
    
        _tprintf( TEXT("Hardware ID : [%s]\n"), PropertyValueBuffer );
    
    #if !NICO_CHAN_TEST
        // BUFFALO Device
        if( (_tcsstr( (PTCHAR)PropertyValueBuffer, TEXT("VID_0411&PID_0") ) != NULL) ||
          (_tcsstr( (PTCHAR)PropertyValueBuffer, TEXT("VID_0411&PID_1") ) != NULL) )
    #else
        CharUpper( (PTCHAR)tstrHardwareID );
        if( (_tcsstr( (PTCHAR)PropertyValueBuffer, tstrHardwareID ) != NULL) )
    #endif NICO_CHAN_TEST
        {
    
          // ここからはドライブレターとのマッチングで使用する情報を取得する
    
          // VID/PIDが一致した DEVINSTを使用して
          // "DiskDrive" デバイス クラスの Device Instance Handleを取得する
          DEVINST devInstChild;
          dwRet = CM_Get_Child( &devInstChild, DevInfoData.DevInst, 0 );
          if( dwRet != CR_SUCCESS )
          {
            _tprintf( TEXT("CM_Get_Child() Err.[%d][%d]\n"), dwRet, GetLastError() );
            goto EndLabel;
          }
    
          TCHAR pszDevInstanceId[MAX_PATH];
    
          dwRet = CM_Get_Device_ID( devInstChild, pszDevInstanceId, MAX_PATH, 0 );
          if( dwRet != CR_SUCCESS )
          {
            _tprintf( TEXT("CM_Get_Device_ID() Err.[%d][%d]\n"), dwRet, GetLastError() );
            goto EndLabel;
          }
          _tprintf( TEXT("Device Instance ID : [%s]\n"), pszDevInstanceId );
    
    
          // Instance Pathを取得する
          ULONG ulSize;
    
          dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&VolumeClassGuid, pszDevInstanceId, 0 );
          if( dwRet != CR_SUCCESS )
          {
            _tprintf( TEXT("CM_Get_Device_Interface_List_Size() Err.[%d][%d]\n"), dwRet, GetLastError() );
            goto EndLabel;
          }
          _tprintf( TEXT("CM_Get_Device_Interface_List_Size[%d]\n"), ulSize );
    
    
          RegSize = (ulSize * sizeof(TCHAR)) +1; // +1:GetVolumeNameForVolumeMountPoint()で 最後に '\'が必要なため
          LPTSTR pszList = (LPTSTR) malloc( RegSize );
    
          if( pszList == NULL )
          {
            _tprintf( TEXT("malloc() Err.[%d][%d]\n"), RegSize, GetLastError() );
            goto EndLabel;
          }
    
          dwRet = CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pszDevInstanceId, pszList, ulSize, 0 );
    
          if( dwRet != CR_SUCCESS )
          {
            _tprintf( TEXT("CM_Get_Device_Interface_List() Err.[%d][%d]\n"), dwRet, GetLastError() );
            free(pszList);
            goto EndLabel;
          }
          _tprintf( TEXT("Instance Path : [%s]\n"), pszList );
    
    
    #if 1
    // ====> 
          if ( *pszList == NULL )
          {
            ULONG  ulDeviceIDsListSize    = 0;
            ULONG  ulDeviceInterfaceListSize = 0;
            PTCHAR pDeviceIDsList      = NULL;
            PTCHAR pDeviceInterfacesList   = NULL;
    
            if( CM_Get_Device_ID_List_Size( &ulDeviceIDsListSize, pszDevInstanceId, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
            {
              ulDeviceIDsListSize *= sizeof(TCHAR);
              pDeviceIDsList = (PTCHAR)malloc( ulDeviceIDsListSize );
    
              if ( pDeviceIDsList )
              {
                if( CM_Get_Device_ID_List( pszDevInstanceId, pDeviceIDsList, ulDeviceIDsListSize, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
                {
                  if ( CM_Get_Device_Interface_List_Size( &ulDeviceInterfaceListSize, (LPGUID)&VolumeClassGuid, pDeviceIDsList, 0 ) == CR_SUCCESS )
                  {
                    ulDeviceInterfaceListSize *= sizeof(TCHAR);
                    pDeviceInterfacesList = (PTCHAR)malloc( ulDeviceInterfaceListSize );
                    if ( pDeviceInterfacesList )
                    {
                      if ( CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pDeviceIDsList, pDeviceInterfacesList, ulDeviceInterfaceListSize, 0 ) == CR_SUCCESS )
                      {
                        free(pszList);
                        pszList = NULL;
                        RegSize = 0;
    
                        RegSize = ulDeviceInterfaceListSize + sizeof( TCHAR );
                        pszList = (PTCHAR)malloc( RegSize );
                        ZeroMemory( pszList, RegSize );
                        CopyMemory( pszList, pDeviceInterfacesList, ulDeviceInterfaceListSize);
                      }
                      free( pDeviceInterfacesList );
                    }
                  }
                }
                free( pDeviceIDsList );
              }
            }
          }
    // <==== 
    #endif
    
    
          ulSize = _tcslen( pszList );
          pszList[ulSize] = '\\';
          pszList[ulSize+1] = NULL;
          _tprintf( TEXT("Instance Path2[%d] : [%s]\n"), ulSize, pszList );
    
          dwRet = GetVolumeNameForVolumeMountPoint( pszList, pszVolumeName, MAX_PATH );
          if( dwRet == 0 )
          {
            _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
            free(pszList);
            goto EndLabel;
          }
    
          _tprintf( TEXT("VolumeName : [%s]\n"), pszVolumeName );
    
          if ( !(_tcsnicmp( pszVolumeName, pszTargetVolumeName, _tcslen(pszTargetVolumeName) )) )
          {
            _tprintf( TEXT("!!! Note !!!\n") );
            _tprintf( TEXT("\tHardware ID    : [%s]\n"), PropertyValueBuffer );
            _tprintf( TEXT("\tSymbolic Link Name : [%s]\n"), pszList );
            _tprintf( TEXT("\tVolumeName     : [%s]\n"), pszVolumeName );
            _tprintf( TEXT("!!!! Target volume devie is found !!!!\n") );
            MatchFound = true;
          }
     
          free(pszList);
        }
    
    EndLabel:
        free(PropertyValueBuffer);
        InterfaceIndex++;
    
      }//while(MatchFound) 
    
      SetupDiDestroyDeviceInfoList( DeviceInfoTable );
    
      return 0;
    }
    
    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月20日 5:04
  • ニコチャン大王さん、お世話になっております。
    お忙しいところ、ご回答とソースの提示をいただき、ありがとうございます。

    新規プロジェクトでソースをそのままコピーして実施してみたのですが、

    Target Drive : [E:]
    Physical Device Name : [\Device\Harddisk1\DP(1)0-0+4]
    !!! Note !!!
    TargetVolumeName : [\\?\Volume{740609f6-7fc5-11de-be0b-005056c00008}\]
    
    Hardware ID : [USB\VID_0411&PID_0xxx&REV_0100]
    Device Instance ID : [USBSTOR\DISK&VEN_BUFFALO&PROD_xxxxxx&REV_1.00\000000000000&0]
    CM_Get_Device_Interface_List_Size[1]
    Instance Path : []
    Instance Path2[0] : [\]
    VolumeName : [\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\]
    Hardware ID : [USB\VID_2101&PID_1402&REV_0001]
    

    となり、"!!!! Target volume devie is found !!!!" を見ることができませんでした。

    対象としているものが、USBメモリのような単純なマスストレージ製品でなく、USB接続の選択でマスストレージを行うタイプになります。
    プリンタやデジカメのようなSDカードを差して接続するとマスストレージ接続を選択できるようになる感じです。

    Volumeクラスに入っていると思っていますが、そこから思い違いをしているのでしょうか。

    2010年4月23日 1:19
  • USB メモリで試すとどうなりますか?

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月23日 1:23
  • ニコチャン大王さん、お世話になっております。
    素早いご回答を頂きながら、こちらが遅くなり、失礼申し訳ありません。


    # 職場はUSBメモリ使用禁止でしたので自宅で行ってみました。
     XP HomeEdtionでUSBメモリを参照しても、VID/PID番号が出ないのですね;;;
     USBViewを自宅にも入れて調べました。


    2つのUSBメモリで実施しました。

    ① Hagiwara Sys-ComのUSBメモリ
    VID:0x0693
    PID:0x0018

    実行結果
    ------------------------------------
    Target Drive : [K:]
    Physical Device Name : [\Device\HarddiskVolume7]
    !!! Note !!!
    TargetVolumeName : [\\?\Volume{87f5c39f-3d69-11de-8421-002511037994}\]

    Hardware ID : [USB\VID_04BB&PID_052E&REV_0100]
    Hardware ID : [USB\VID_0693&PID_0018&REV_0100]
    Hardware ID : [USB\VID_0BDA&PID_0151&REV_5195]
    ------------------------------------


    ② メーカ不明USBメモリ
    VID:0x1307
    PID:0x0163

    実行結果
    ------------------------------------
    Target Drive : [O:]
    Physical Device Name : [\Device\HarddiskVolume8]
    !!! Note !!!
    TargetVolumeName : [\\?\Volume{87f5c365-3d69-11de-8421-002511037994}\]

    Hardware ID : [USB\VID_04BB&PID_052E&REV_0100]
    Hardware ID : [USB\VID_0BDA&PID_0151&REV_5195]
    Hardware ID : [USB\VID_1307&PID_0163&REV_0100]
    ------------------------------------


    このような結果となりました。

    XP Homeと Vista Homeで試してみましたが、
    どちらも"!!!! Target volume devie is found !!!!" を見ることができませんでした。

    2010年4月27日 16:40
  • プログラム実行時のパラメータ指定はどのようにされているのでしょうか?
    プログラム実行時のパラメータ入力も示して頂けますか?

    (上記ログを見ると、2nd パラメータで指定した "VID_xxxx&PID_xxxx" と合致していないように見受けられます。
      VID / PID の指定部分は Double Quotation '"' で囲っているのでしょうか?)

    先に示したコードをそのまま使っているのであれば、少なくとも USB メモリではうまく動くはずです。
    実際、動作検証を行ったコードをそのままコピペしましたので...

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年4月28日 0:55
  • ニコチャン大王さん、お世話になっております。

    パラメータ指定ですが、

    ①の場合では、
     DOS> Device.exe K: "VID_0693&PID_0"

    ②の場合では、
     DOS> Device.exe O: "VID_1307&PID_0"

    で実行しました。
    ソースコードを提示いただいた時の説明に従い、第2引数には、ダブルクォーテーションを付けています。

    外して実行すると、
     『’PID_0’は、内部コマンドまたは外部コマンド・・・認識されていません。』
    とエラーになります。

    Debug実行時に、tstrHardwareID の内容を確認しましたが、"VID_0411&PID_0"と設定されていました。


    本日、自宅に帰った際、単純な USB-HDDドライブも試してみます。

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    • 回答としてマークされていない TDM850 4TX 2010年5月15日 12:40
    2010年5月6日 9:01
  • ニコチャン大王さん、お世話になっております。

    他のUSB接続のマスストレージデバイスで試してみました。


    ③ BUFFALO ポータブルUSB-HDD  80GB
     VID 0x0411
     PID 0x008D
    実行結果
    ------------------------------------
    >Device.exe M: "VID_0411&PID_0"
    Target Drive : [M:]
    Not REMOVABLE
    ------------------------------------


    ④ I-O DATA  USB-HDD  500GB
     VID 0x04BB
     PID 0x010F

    実行結果
    ------------------------------------
    >Device.exe N: "VID_04BB&PID_0"
    Target Drive : [N:]
    Not REMOVABLE
    ------------------------------------

    どちらもリムーバブル判定で引っかかりました。

    USB大容量記憶装置は、すべてリムーバブルと思っていましたが、
    そうでは無いのですね。

    2010年5月6日 14:50
  • デバッガ上でちゃんと確認されているのでしょうか?

     

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:40
    2010年5月6日 16:17
  • ニコチャン大王さん、お世話になっております。
    お早うございます。


    デバッグでステップ実行してみたところ、#if1として追加いただいた部分の、
    CM_Get_Device_ID_List()で CR_INVALID_POINTERとなっていました。

    そのため、最後の GetVolumeNameForVolumeMountPoint()が "\"で実行することになり、
    Cドライブの値を取得していました。

    CM_Get_Device_ID_List_Size()のサイズ取得で ulDeviceIDsListSizeが 0でした。
    pszDevInstanceId には、"\\?\USBSTOR\DISK&VEN_BUFFALO&PROD_XXXXXX&Rev_1.00#xxxxxxxxxxxx&0#{GUID}" を使用しています。

     

    ニコチャン大王さんがビルドされたのは、WDK環境とありますが、
    下名は WDK 6001.18001を使用しています。
    適宜ライブラリを変更するようにとのことですが、使用するバージョンは関係しますでしょうか。

    2010年5月7日 1:30
  • 再びこんばんは。

    >適宜ライブラリを変更するようにとのことですが、使用するバージョンは関係しますでしょうか。

    WDK のバージョンに依存した問題ではないと思います。
    先に示したコードは、USB メモリでのみ検証したもので、USB HDD の場合を考慮していません。
    ただ、通常の USB メモリでもうまく動作しないのが、私としては非常に不思議なのですが....

    USB HDD の場合、兄弟デバイスをチェックする必要があります。

    一応、下記コードで USB メモリと USB HDD および USB CD-ROM ドライブで正しく機能することを確認しましたので、
    試してみてください。

    ------------------------------------------------------------------------------
    #define UNICODE
    #define _UNICODE

    #include <stdio.h>
    #include <malloc.h>
    #include <windows.h>
    #include <tchar.h>
    #include <setupapi.h> // SetupDixxx
    #include <Cfgmgr32.h> // CM_Get_xxx
    #include <initguid.h>
    #include <winioctl.h>
    #include <usbiodef.h>


    #pragma comment( lib, "setupapi.lib" )
    #pragma comment( lib, "Cfgmgr32.lib" )

    #define NICO_CHAN_TEST  TRUE


    void Usage
    (
        PTSTR   BinaryName
    )
    {
        _tprintf( (TEXT("\n")
                   TEXT("Usage:                                \n")
                   TEXT("      %s <drive:> <VID_xxxx&PID_xxxx> \n")
                   TEXT("Ex.]                                  \n")
                   TEXT("      %s E: \"VID_0411&PID_0\"        \n")), BinaryName, BinaryName );
    }


    int __cdecl _tmain
    (
        int argc,
        TCHAR* argv[]
    )
    {
        DWORD   dwRet;
        TCHAR   strDrive[8];
        TCHAR   pszPhysicalDeviceName[MAX_PATH];
        TCHAR   pszTargetVolumeName[MAX_PATH];
        TCHAR   pszVolumeName[MAX_PATH];

    //_asm int 3;

        /* ■1 ドライブから物理名とボリューム名を取得 */
    #if !NICO_CHAN_TEST
        wsprintf( strDrive, TEXT("E:\\") );
    #else
        PTSTR   tstrHardwareID;

        if ( argc != 3 )
        {
            Usage( argv[0] );
            return 1;
        }
        else
        {
            TCHAR   DriveLetter = argv[1][0];

            if ( !(( DriveLetter >= _T('a') && DriveLetter <= _T('z') )  ||
                   ( DriveLetter >= _T('A') && DriveLetter <= _T('Z') )) ||
                  ( argv[1][1] != _T(':')) || ( argv[1][2] != _T('\0') ) )
            {
                Usage( argv[0] );
                return 1;
            }
        }

        _tprintf( TEXT("Target Drive : [%s]\n"), argv[1] );
        wsprintf( strDrive, TEXT("%s\\"), argv[1] );

        tstrHardwareID = argv[2];
    #endif

        UINT drvType = GetDriveType( strDrive );

    #if 0
        if( drvType == DRIVE_REMOVABLE )
        { // リムーバブルのみ
            strDrive[2] = NULL;
            dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
            if(dwRet == 0)
            {
                _tprintf( TEXT("QueryDosDevice() Error! [%d]\n"), GetLastError() );
                return 1;
            }

            _tprintf( TEXT("Physical Device Name : [%s]\n"), pszPhysicalDeviceName );

            // ボリューム名を取得
            strDrive[2] = '\\';
            strDrive[3] = NULL;
            dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszTargetVolumeName, MAX_PATH );

            if( dwRet == 0 )
            {
                _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
                return 1;
            }

            _tprintf( TEXT("!!! Note !!!\n")
                      TEXT("\tTargetVolumeName : [%s]\n\n"), pszTargetVolumeName );
        }
        else
        {
            _tprintf( TEXT("Not REMOVABLE\n"), strDrive );
            return 1;
        }
    #else
        strDrive[2] = NULL;
        dwRet = QueryDosDevice( strDrive, pszPhysicalDeviceName, MAX_PATH );
        if(dwRet == 0)
        {
            _tprintf( TEXT("QueryDosDevice() Error! [%d]\n"), GetLastError() );
            return 1;
        }

        _tprintf( TEXT("Physical Device Name : [%s]\n"), pszPhysicalDeviceName );

        // ボリューム名を取得
        strDrive[2] = '\\';
        strDrive[3] = NULL;
        dwRet = GetVolumeNameForVolumeMountPoint( strDrive, pszTargetVolumeName, MAX_PATH );

        if( dwRet == 0 )
        {
            _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
            return 1;
        }

        _tprintf( TEXT("!!! Note !!!\n")
                  TEXT("\tTargetVolumeName : [%s]\n\n"), pszTargetVolumeName );
    #endif

        /* ■2 Device Instance を取得 */
        HDEVINFO                    DeviceInfoTable = INVALID_HANDLE_VALUE;
        SP_DEVICE_INTERFACE_DATA    DevInterfaceData;
        SP_DEVINFO_DATA             DevInfoData;

        DWORD   InterfaceIndex = 0;
        DWORD   StatusLastError = 0;
        DWORD   RegType;
        DWORD   RegSize;   //使いまわしあり
        DWORD   StructureSize = 0;
        PBYTE   PropertyValueBuffer = NULL;
        BOOL    MatchFound = false;
        DWORD   ErrorStatus;

        ZeroMemory(&DevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
        DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);


        // USBデバイス用の情報セットを取得
        DeviceInfoTable = SetupDiGetClassDevs( &GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
        if ( DeviceInfoTable == INVALID_HANDLE_VALUE )
        {
            _tprintf( TEXT("DeviceInfoTable == INVALID_HANDLE_VALUE \n") );
            return 1;
        }

        while( !MatchFound )
        {
            DevInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
            if( SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &GUID_DEVINTERFACE_USB_DEVICE, InterfaceIndex, &DevInterfaceData) )
            {
                ErrorStatus = GetLastError();
                if( ERROR_NO_MORE_ITEMS == ErrorStatus )
                { //情報セットの終端
                    break;
                }
            }
            else
            { // 予期していないエラー。基本的に起こりえないと思われる
                ErrorStatus = GetLastError();
                break;
            }

            // USBデバイス情報の詳細を取得
            DevInfoData.cbSize = sizeof( SP_DEVINFO_DATA );
            SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, &DevInfoData);

            // 詳細情報のデータを取得
            SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, NULL, 0, &RegSize );
            PropertyValueBuffer = (BYTE*) malloc( RegSize * sizeof(BYTE) );
            SetupDiGetDeviceRegistryProperty( DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &RegType, PropertyValueBuffer, RegSize, NULL );

            CharUpper( (PTCHAR)PropertyValueBuffer );

            _tprintf( TEXT("Hardware ID : [%s]\n"), PropertyValueBuffer );

    #if !NICO_CHAN_TEST
            // BUFFALO Device
            if( (_tcsstr( (PTCHAR)PropertyValueBuffer, TEXT("VID_0411&PID_0") ) != NULL) ||
                (_tcsstr( (PTCHAR)PropertyValueBuffer, TEXT("VID_0411&PID_1") ) != NULL) )
    #else
            CharUpper( (PTCHAR)tstrHardwareID );
            if( (_tcsstr( (PTCHAR)PropertyValueBuffer, tstrHardwareID ) != NULL) )
    #endif NICO_CHAN_TEST
            {
                DEVINST     devInstChild;
                TCHAR       pszDevInstanceId[MAX_PATH];
                ULONG       ulSize;
                LPTSTR      pszList;

                // ここからはドライブレターとのマッチングで使用する情報を取得する

                // VID/PIDが一致した DEVINSTを使用して
                // "DiskDrive" デバイス クラスの Device Instance Handleを取得する

                dwRet = CM_Get_Child( &devInstChild, DevInfoData.DevInst, 0 );
                if( dwRet != CR_SUCCESS )
                {
                    _tprintf( TEXT("CM_Get_Child() Err.[%d][%d]\n"), dwRet, GetLastError() );
                    goto EndLabel;
                }

    LOOP_LABEL:

                dwRet = CM_Get_Device_ID( devInstChild, pszDevInstanceId, MAX_PATH, 0 );
                if( dwRet != CR_SUCCESS )
                {
                    _tprintf( TEXT("CM_Get_Device_ID() Err.[%d][%d]\n"), dwRet, GetLastError() );
                    goto EndLabel;
                }
                _tprintf( TEXT("Device Instance ID : [%s]\n"), pszDevInstanceId );


                // Instance Pathを取得する

                dwRet = CM_Get_Device_Interface_List_Size( &ulSize, (LPGUID)&VolumeClassGuid, pszDevInstanceId, 0 );
                if( dwRet != CR_SUCCESS )
                {
                    _tprintf( TEXT("CM_Get_Device_Interface_List_Size() Err.[%d][%d]\n"), dwRet, GetLastError() );
                    goto EndLabel;
                }
                _tprintf( TEXT("CM_Get_Device_Interface_List_Size[%d]\n"), ulSize );


                RegSize = (ulSize * sizeof(TCHAR)) +1; // +1:GetVolumeNameForVolumeMountPoint()で 最後に '\'が必要なため
                pszList = (LPTSTR) malloc( RegSize );

                if( pszList == NULL )
                {
                    _tprintf( TEXT("malloc() Err.[%d][%d]\n"), RegSize, GetLastError() );
                    goto EndLabel;
                }

                dwRet = CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pszDevInstanceId, pszList, ulSize, 0 );

                if( dwRet != CR_SUCCESS )
                {
                    _tprintf( TEXT("CM_Get_Device_Interface_List() Err.[%d][%d]\n"), dwRet, GetLastError() );
                    free(pszList);
                    goto EndLabel;
                }
                _tprintf( TEXT("Instance Path : [%s]\n"), pszList );


    #if 1
    // ====>
                if ( *pszList == NULL )
                {
                    ULONG   ulDeviceIDsListSize       = 0;
                    ULONG   ulDeviceInterfaceListSize = 0;
                    PTCHAR  pDeviceIDsList            = NULL;
                    PTCHAR  pDeviceInterfacesList     = NULL;

                    if( CM_Get_Device_ID_List_Size( &ulDeviceIDsListSize, pszDevInstanceId, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
                    {
                        ulDeviceIDsListSize *= sizeof(TCHAR);
                        pDeviceIDsList = (PTCHAR)malloc( ulDeviceIDsListSize );

                        if ( pDeviceIDsList )
                        {
                            if( CM_Get_Device_ID_List( pszDevInstanceId, pDeviceIDsList, ulDeviceIDsListSize, CM_GETIDLIST_FILTER_REMOVALRELATIONS ) == CR_SUCCESS )
                            {
                                if ( CM_Get_Device_Interface_List_Size( &ulDeviceInterfaceListSize, (LPGUID)&VolumeClassGuid, pDeviceIDsList, 0 ) == CR_SUCCESS )
                                {
                                    ulDeviceInterfaceListSize *= sizeof(TCHAR);
                                    pDeviceInterfacesList = (PTCHAR)malloc( ulDeviceInterfaceListSize );
                                    if ( pDeviceInterfacesList )
                                    {
                                        if ( CM_Get_Device_Interface_List( (LPGUID)&VolumeClassGuid, pDeviceIDsList, pDeviceInterfacesList, ulDeviceInterfaceListSize, 0 ) == CR_SUCCESS )
                                        {
                                            free(pszList);
                                            pszList = NULL;
                                            RegSize = 0;

                                            RegSize = ulDeviceInterfaceListSize + sizeof( TCHAR );
                                            pszList = (PTCHAR)malloc( RegSize );
                                            ZeroMemory( pszList, RegSize );
                                            CopyMemory( pszList, pDeviceInterfacesList, ulDeviceInterfaceListSize);
                                        }
                                        free( pDeviceInterfacesList );
                                    }
                                }
                            }
                            free( pDeviceIDsList );
                        }
                    }
                }
    // <====
    #endif


                ulSize = _tcslen( pszList );
                pszList[ulSize] = '\\';
                pszList[ulSize+1] = NULL;
                _tprintf( TEXT("Instance Path2[%d] : [%s]\n"), ulSize, pszList );

                dwRet = GetVolumeNameForVolumeMountPoint( pszList, pszVolumeName, MAX_PATH );
                if( dwRet == 0 )
                {
                    _tprintf( TEXT("GetVolumeNameForVolumeMountPoint() Error! [%d]\n"), GetLastError() );
                    free(pszList);
                    goto EndLabel;
                }

                _tprintf( TEXT("VolumeName : [%s]\n"), pszVolumeName );

                if ( !(_tcsnicmp( pszVolumeName, pszTargetVolumeName, _tcslen(pszTargetVolumeName) )) )
                {
                    _tprintf( TEXT("!!! Note !!!\n") );
                    _tprintf( TEXT("\tHardware ID        : [%s]\n"), PropertyValueBuffer );
                    _tprintf( TEXT("\tSymbolic Link Name : [%s]\n"), pszList );
                    _tprintf( TEXT("\tVolumeName         : [%s]\n"), pszVolumeName );
                    _tprintf( TEXT("!!!! Target volume devie is found !!!!\n") );
                    MatchFound = true;
                }
                else
                {
                    DEVINST     SiblingDevInst;

                    if ( CM_Get_Sibling( &SiblingDevInst, devInstChild, 0 ) == CR_SUCCESS )
                    {
                        devInstChild = SiblingDevInst;
                        goto LOOP_LABEL;
                    }
                }

                free(pszList);
            }

    EndLabel:
            free(PropertyValueBuffer);
            InterfaceIndex++;

        }//while(MatchFound)

        SetupDiDestroyDeviceInfoList( DeviceInfoTable );

        return 0;
    }
    ------------------------------------------------------------------------------

    先にご提示いただいた実行結果を見て疑問に思ったのですが...
    なぜ PID を全部指定しないのでしょうか?

    • 回答としてマーク TDM850 4TX 2010年5月15日 12:39
    2010年5月7日 14:03
  • ニコチャン大王さん、お世話になっております。

    返信がまたも遅くなり、まことに申し訳ありません。
    また、何回も改修点を提示して頂きありがとうございます。

    今回いただきましたソースで、USBメモリ、単一HDDでの検出はできました!!!!!

    しかし、いくつかの開発中のデバイスを識別することはできませんでした。
    認識できたデバイスもあります!

    デバイス側に何らかの特殊処理があるのか、足りていない処理があるのか、
    どちらにせよ、一般(規格を守っている)デバイスとは違うようですので、
    こちらでの質問を完了とさせて頂きたいと思います。


    何ヶ月もの長きにわたりサポートして頂き、何と言っていいのか、感謝の気持ちでいっぱいです。
    ご協力、まことにありがとうございました。
    m(__)m


    > なぜ PID を全部指定しないのでしょうか?
    PIDを個別に指定しても良いのですが、このロジックを利用しようとしているプログラムでは、
    PIDの番号でグループ化があります。
    そのため、固定ではなくワイルドカードと良いますか、最後まで判定しないようにと考えていました。

     

    2010年5月15日 12:39
  • "TDM850 4TX" さんにお詫びすることがあります...

    このスレッドは既に「解決済み」となっていますが、サンプル コードを提示させて頂いた者として、
    あえて訂正および追記させていただきます。

    (理由は、別スレッドで "とっちゃん" さんが発言されている
      「自分の投稿がたとえ 100 年後に参照されたとしても、その発言に責任を持てるよう心がけるべき!」
      という言葉に非常に共鳴し、自身の恥をさらすことになりますが、自戒の念をこめて訂正させて頂きます。)

    先に示したコードをご覧になった方は既にお気づきかと思いますが、最終的に示したコードには、ごく初歩的な
    メモリ リークというバグがあります。
    (もしかしたら、これ以外にも Bug はあるかもしれませんが...)
    Bug は、以下の箇所です。

    ------------------------------------------------------------------------
    <Bug ありコード>
    ....
                if ( !(_tcsnicmp( pszVolumeName, pszTargetVolumeName, _tcslen(pszTargetVolumeName) )) )
                {
                    _tprintf( TEXT("!!! Note !!!\n") );
                    _tprintf( TEXT("\tHardware ID        : [%s]\n"), PropertyValueBuffer );
                    _tprintf( TEXT("\tSymbolic Link Name : [%s]\n"), pszList );
                    _tprintf( TEXT("\tVolumeName         : [%s]\n"), pszVolumeName );
                    _tprintf( TEXT("!!!! Target volume devie is found !!!!\n") );
                    MatchFound = true;
                }
                else
                {
                    DEVINST     SiblingDevInst;

                    if ( CM_Get_Sibling( &SiblingDevInst, devInstChild, 0 ) == CR_SUCCESS )
                    {
                        devInstChild = SiblingDevInst;
                        goto LOOP_LABEL;
                    }
                }

                free(pszList);  // ☆ <=== ここだと、goto で jump した時にメモリ リークを起こします
    ....
    ------------------------------------------------------------------------
    <修正コード>
    ....
                if ( !(_tcsnicmp( pszVolumeName, pszTargetVolumeName, _tcslen(pszTargetVolumeName) )) )
                {
                    _tprintf( TEXT("!!! Note !!!\n") );
                    _tprintf( TEXT("\tHardware ID        : [%s]\n"), PropertyValueBuffer );
                    _tprintf( TEXT("\tSymbolic Link Name : [%s]\n"), pszList );
                    _tprintf( TEXT("\tVolumeName         : [%s]\n"), pszVolumeName );
                    _tprintf( TEXT("!!!! Target volume devie is found !!!!\n") );
                    MatchFound = true;
                    free(pszList);
                }
                else
                {
                    DEVINST     SiblingDevInst;

                    free(pszList);
                    if ( CM_Get_Sibling( &SiblingDevInst, devInstChild, 0 ) == CR_SUCCESS )
                    {
                        devInstChild = SiblingDevInst;
                        goto LOOP_LABEL;
                    }
                }
    ....
    ------------------------------------------------------------------------

    実は、この Bug に関しては、投稿した直後から気付いていたのですが、

    「どうせサンプルだし、単なるテスト目的のアプリなので、プロセスが終了されれば実害はないし...」

    と言う非常に安易な気持から、現在まで放置してしまいました。
    "TDM850 4TX" さんには大変申し訳ありませんでした。

    また、このコードはあくまでも "TDM850 4TX" さんが当初示されたサンプル コードをベースに、

    「オリジナル コードを極力変更することなく、目的の機能を実現させる」

    という点に着目して示したものです。
    なので (投稿しておきながら、また無責任な発言で申し訳ありませんが...) 、この実装方法が必ずしも
    適切である訳ではないことにご注意ください。

    例えば、本来 while() あるいは for() 文でループ処理させるべき兄弟デバイスのチェックを、最終コードでは
    無理やり goto でループさせていますし、そもそも USB デバイスの DevNode にどのような Device Class の
    DevNode が接続されているのかもチェックしていません。
    (現状では、"DiskDrive" デバイス クラスに直接接続されていることが前提となってしまっています。)
    なので、複合デバイスなのど場合は、期待通りの結果を得ることができないと思います。
    実際 "TDM850 4TX" さんがターゲットとされているデバイスでは期待通りの結果にならないのも、
    おそらくこの点にあると思います。

    なので、Windows Driver Model でのドライバ アーキテクチャを理解する必要は無いにしても、
    デバイス スタック構造の基本的な概念を理解した上で、先のサンプルを参考にして、
    適切に DevNode チェックを行うよう修正していただければ...と存じます。
    (間違っても、私の示したコードを鵜呑みにしないでください。)

    ここまで書いて、「やっぱり、相変わらず無責任な投稿だ...」と再認識してしまうような内容ですが、
    なにとぞご容赦ください。

    2010年5月27日 11:30