トップ回答者
USBドライブのVID/PIDを調べる方法について

質問
-
回答
-
既に解決されているかもしれませんが。。。。
私も以前に同じことを考えて、実際に出来ました。
参考にしたのは、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
-
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
-
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
-
再びこんばんわ。
話がややこしくなりそうなので、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
-
再びこんばんわ。
うーん。。。ちょっとまだ理解してもらえていないよなので、気になった点をいくつか...> "\\?\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
-
全く検証していませんが、以下のような感じの処理を追加すれば、うまくいくはずです。
-----------------------------------------------------------------------
#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
-
コマンド プロンプトで、"MountVol" を実行してみてください。
現在のマウント ポイントとボリューム名の一覧が表示されます。
- 回答としてマーク TDM850 4TX 2010年5月15日 12:41
-
"\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"
↑ これはどのドライブ レターのモノでしたか?
また、そのドライブ レターが割り当てられているデバイスは何ですか?
おそらく E: 以外に、別の USB ストレージ デバイスが接続されているためと思われます。
- 回答としてマーク TDM850 4TX 2010年5月15日 12:41
-
MountVol コマンドの出力結果に、以下のマウント ポイントは出力されていないのですか?
"\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"
また、使用している USB デバイスの種類は何でしょうか?
1つの USB デバイスでも、複数のインターフェイス (ボリューム等)をもつものあります。
デバイスが1つだけだからと言って、ボリュームが1つだけとは限りません。
とにかく、MountVol での出力結果を見ないと、なんとも言えません。
- 回答としてマーク TDM850 4TX 2010年5月15日 12:41
-
>"\\?\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
-
返信が遅くなってしまったので、既に解決してるかもしれませんが。。。
たぶん、単純に文字列操作に問題があるんだと思います。
少なくとも、ストレージ デバイスがUSBメモリなら、先に示した感じの実装で必ずボリューム名が取れるはずです。
strstr() での文字列チェックの所で、ちゃんと判別できているかを再度確認するのが先決だと思います。
- 回答としてマーク TDM850 4TX 2010年5月15日 12: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
-
-
プログラム実行時のパラメータ指定はどのようにされているのでしょうか?
プログラム実行時のパラメータ入力も示して頂けますか?(上記ログを見ると、2nd パラメータで指定した "VID_xxxx&PID_xxxx" と合致していないように見受けられます。
VID / PID の指定部分は Double Quotation '"' で囲っているのでしょうか?)先に示したコードをそのまま使っているのであれば、少なくとも USB メモリではうまく動くはずです。
実際、動作検証を行ったコードをそのままコピペしましたので...- 回答としてマーク TDM850 4TX 2010年5月15日 12:40
-
-
再びこんばんは。
>適宜ライブラリを変更するようにとのことですが、使用するバージョンは関係しますでしょうか。
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];
#endifUINT 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
すべての返信
-
まず、始めに断っておきますが、きちんと最後まで確認していません。
できるかもしれないと思ったことを書いていますので、もしかしたらできないかもしれませんし、無駄な手順があるかもしれません。
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
-
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
-
既に解決されているかもしれませんが。。。。
私も以前に同じことを考えて、実際に出来ました。
参考にしたのは、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
-
かびるんるんさん、レス、ありがとうございます。
試行錯誤を繰り返していますが、未だ解決できていません。
頂いた内容で、質問があります。
● 手順1について
記載から考えると、QueryDosDevice()で取得したパスを
GetVolumeNameForVolumeMountPoint() で使用するように思えるのですが、
エラーとなってしまいます。
GetVolumeNameForVolumeMountPoint() のMSDN説明を読み、
ディレクトリのような最終に "\0"となるようにしていますが、エラーとなります。
(例えば)"F:\"で取得したパスは使えるのでしょうか?
● 手順2について
Instance Path とは、具体的には何の関数を使用しておられますでしょうか?
CM_Get_Device_Interface_List() の戻りが NULLになってしまうのは、
CM_Get_Device_ID()で Child Device が選びきれていないという事になりますでしょうか? -
おしいところまで来ていると思うのですが、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; }
-
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
-
かびるんるんさん、こんにちは。
お世話になっております。ご回答ありがとうございます。
重ねて質問となり、済みません。
● GetVolumeNameForVolumeMountPoint() について
下名の説明がおかしかったようです。
NULL 終端の文字列として渡してみたのですが、エラーとなっていました。
ドライブレター("F:\")からは、
"\Device\Harddisk1\DP(1)0-0+4" というような文字列を取得していますが、
これは見当違いの値となりますでしょうか?
CM_Get_Device_ID()から取得した値を見れていないので、違いが分かっていません。
● GUIDについて
現状、GUID_DEVINTERFACE_USB_DEVICE で検索を行っています。
GUID_DEVINTERFACE_USB_HOST_CONTROLLER でも行ってみます。 -
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
-
かびるんるんさん、こんにちは。
お世話になっております。
早速のご回答ありがとうございます。
済みません。下名の情報も間違っているところがありました。
"\Device\Harddisk1\DP(1)0-0+4"
これはご指摘の通り、QueryDosDevice() で取得した値になります。
Volume Name は、 "F:\\\0" (F:\)で実行して、、"\\?\Volume\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
を取得していました。
間違った報告で、詳細な説明をいただき、済みません。
GUID_CLASS_USB_DEVICE
かびるんるんさんの実現できた処理に、先ずはあわせて、試行錯誤してみます。
ありがとうございます。 -
こんにちは。フォーラムオペレーターの高橋春樹です。
Azuleanさん、かびるんるんさん
アドバイスの投稿有難うございました。TDM850 4TXさん
MSDNフォーラムのご利用有難うございました。今回、Azuleanさん、かびるんるんさんからの投稿が、有用な情報であったと思いましたので、
一旦、回答マークを付けさせてもらいました。もし、試行錯誤するとのことですが、もし新たな情報がありましたらご投稿して頂きたいと思ってます。
尚、回答マークは問題解決を意味するものではないので、その他アドバイスがありましたら
ご投稿の程、宜しくお願いします。
マイクロソフト株式会社 フォーラム オペレーター 高橋春樹 -
ニコチャン大王さん、こんにちは。
お世話になっております。
別作業が入っていて、こちらの作業が停止していました。
昨日より、また作業開始しているのですが、解決できていません。
試行錯誤していて疑問になったことがあります。
> 上記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
-
再びこんばんわ。
話がややこしくなりそうなので、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
-
ニコチャン大王さん、こんにちは。
お世話になっております。
ご回答いただき、ありがとうございます。
> 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の方が付けた返信マークを消したのは、ご多忙の間に、他の方にも見て頂きたかったからです。
ご気分を悪くしたのであれば、失礼しました。 -
再びこんばんわ。
うーん。。。ちょっとまだ理解してもらえていないよなので、気になった点をいくつか...> "\\?\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
-
ニコチャン大王さん、お世話になっております。
参照されている皆さん、こんにちは。まだ理解できていないためか、解決できませんでした。
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
-
全く検証していませんが、以下のような感じの処理を追加すれば、うまくいくはずです。
-----------------------------------------------------------------------
#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
-
ニコチャン大王さん、お世話になっております。
お忙しいところ、ご回答いただき、ありがとうございます。
早速、訂正いただいたソースをマージして試してみました。
GetVolumeNameForVolumeMountPoint()でエラーにはならなくなったのですが、GetVolumeNameForVolumeMountPoint( ドライブレター ) では、
"\\?\Volume{740609f6-7fc5-11de-be0b-005056c00008}\"GetVolumeNameForVolumeMountPoint( Instance Path ) では、
"\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"となり、別の GUIDを取得していました。
この GUIDで何かAPIを通せば、一致することになるのでしょうか?
-
コマンド プロンプトで、"MountVol" を実行してみてください。
現在のマウント ポイントとボリューム名の一覧が表示されます。
- 回答としてマーク TDM850 4TX 2010年5月15日 12:41
-
ニコチャン大王さん、お世話になっております。
早速のご回答、ありがとうございます。
"MountVol" を実行してみたところ、\\?\Volume{740609f6-7fc5-11de-be0b-005056c00008}\
E:\と表示されました。
これは、GetVolumeNameForVolumeMountPoint( ドライブレター ) と同じ値でありました。 -
"\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"
↑ これはどのドライブ レターのモノでしたか?
また、そのドライブ レターが割り当てられているデバイスは何ですか?
おそらく E: 以外に、別の USB ストレージ デバイスが接続されているためと思われます。
- 回答としてマーク TDM850 4TX 2010年5月15日 12:41
-
ニコチャン大王さん、お世話になっております。
早速のご回答、ありがとうございます。
お忙しいところ、何度も済みません。"\\?\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にゴミ情報が残っていたりするものでしょうか?
-
MountVol コマンドの出力結果に、以下のマウント ポイントは出力されていないのですか?
"\\?\Volume{95a9d790-70f4-11dd-bcad-806d6172696f}\"
また、使用している USB デバイスの種類は何でしょうか?
1つの USB デバイスでも、複数のインターフェイス (ボリューム等)をもつものあります。
デバイスが1つだけだからと言って、ボリュームが1つだけとは限りません。
とにかく、MountVol での出力結果を見ないと、なんとも言えません。
- 回答としてマーク TDM850 4TX 2010年5月15日 12:41
-
ニコチャン大王さん、お世話になっております。
お早うございます。"\\?\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に出ています。 -
>"\\?\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
-
ニコチャン大王さん、お世話になっております。
お忙しいところ、ご回答いただき、ありがとうございます。
下名の返信が遅くなり、申し訳ありません。
> 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を疑ったほうが良いということでしょうか? -
返信が遅くなってしまったので、既に解決してるかもしれませんが。。。
たぶん、単純に文字列操作に問題があるんだと思います。
少なくとも、ストレージ デバイスがUSBメモリなら、先に示した感じの実装で必ずボリューム名が取れるはずです。
strstr() での文字列チェックの所で、ちゃんと判別できているかを再度確認するのが先決だと思います。
- 回答としてマーク TDM850 4TX 2010年5月15日 12: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
-
ニコチャン大王さん、お世話になっております。
お忙しいところ、ご回答とソースの提示をいただき、ありがとうございます。新規プロジェクトでソースをそのままコピーして実施してみたのですが、
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クラスに入っていると思っていますが、そこから思い違いをしているのでしょうか。
-
-
ニコチャン大王さん、お世話になっております。
素早いご回答を頂きながら、こちらが遅くなり、失礼申し訳ありません。
# 職場は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 !!!!" を見ることができませんでした。 -
プログラム実行時のパラメータ指定はどのようにされているのでしょうか?
プログラム実行時のパラメータ入力も示して頂けますか?(上記ログを見ると、2nd パラメータで指定した "VID_xxxx&PID_xxxx" と合致していないように見受けられます。
VID / PID の指定部分は Double Quotation '"' で囲っているのでしょうか?)先に示したコードをそのまま使っているのであれば、少なくとも USB メモリではうまく動くはずです。
実際、動作検証を行ったコードをそのままコピペしましたので...- 回答としてマーク TDM850 4TX 2010年5月15日 12:40
-
ニコチャン大王さん、お世話になっております。
パラメータ指定ですが、
①の場合では、
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
-
ニコチャン大王さん、お世話になっております。
他の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大容量記憶装置は、すべてリムーバブルと思っていましたが、
そうでは無いのですね。 -
-
ニコチャン大王さん、お世話になっております。
お早うございます。
デバッグでステップ実行してみたところ、#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を使用しています。
適宜ライブラリを変更するようにとのことですが、使用するバージョンは関係しますでしょうか。 -
再びこんばんは。
>適宜ライブラリを変更するようにとのことですが、使用するバージョンは関係しますでしょうか。
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];
#endifUINT 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
-
ニコチャン大王さん、お世話になっております。
返信がまたも遅くなり、まことに申し訳ありません。
また、何回も改修点を提示して頂きありがとうございます。今回いただきましたソースで、USBメモリ、単一HDDでの検出はできました!!!!!
しかし、いくつかの開発中のデバイスを識別することはできませんでした。
認識できたデバイスもあります!デバイス側に何らかの特殊処理があるのか、足りていない処理があるのか、
どちらにせよ、一般(規格を守っている)デバイスとは違うようですので、
こちらでの質問を完了とさせて頂きたいと思います。
何ヶ月もの長きにわたりサポートして頂き、何と言っていいのか、感謝の気持ちでいっぱいです。
ご協力、まことにありがとうございました。
m(__)m
> なぜ PID を全部指定しないのでしょうか?
PIDを個別に指定しても良いのですが、このロジックを利用しようとしているプログラムでは、
PIDの番号でグループ化があります。
そのため、固定ではなくワイルドカードと良いますか、最後まで判定しないようにと考えていました。 -
"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 チェックを行うよう修正していただければ...と存じます。
(間違っても、私の示したコードを鵜呑みにしないでください。)ここまで書いて、「やっぱり、相変わらず無責任な投稿だ...」と再認識してしまうような内容ですが、
なにとぞご容赦ください。