Здравствуйте, adontz, Вы писали:
A>Здравствуйте, pullover, Вы писали:
A>Буквы бывают у разделов (volume), а не дисков.
Это и есть Volume, так говорит DBT_DEVICEARRIVAL, но этот способ мне не пойдет, т.к.
прога запускается после этого события, т.е. я могу перечислять все USB девайсы, находит диски(volume) и тут мне нужны
имя производителя и буква диска
Re[3]: Узнать букву USB flash диска
От:
Аноним
Дата:
29.06.06 11:29
Оценка:
Здравствуйте, pullover, Вы писали:
P>Здравствуйте, adontz, Вы писали:
A>>Здравствуйте, pullover, Вы писали:
A>>Буквы бывают у разделов (volume), а не дисков.
P>Это и есть Volume, так говорит DBT_DEVICEARRIVAL, но этот способ мне не пойдет, т.к. P>прога запускается после этого события, т.е. я могу перечислять все USB девайсы, находит диски(volume) и тут мне нужны P>имя производителя и буква диска
если вам несложно, то напишите пожалуйста как вы это делаешь, мне тоже надо...
Здравствуйте, pullover, Вы писали:
P>Устройство уже подключено, итерируя P>с помощью SetupDiХХХ нахожу все класса DiskDrive. P>как теперь найти их буквы?
Приблизительно так
.
.
.
SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE,...
SetupDiEnumDeviceInfo(hDevInfo, ...
// Device class USB ?
CM_Get_DevNode_Registry_PropertyW
CompareDevGUIDs(&GUID_DEVCLASS_USB, ...);
// Device class diskdrive ?
CM_Get_Child
CM_Get_DevNode_Registry_PropertyW
CompareDevGUIDs(&GUID_DEVCLASS_DISKDRIVE, ...
// Device class volume ?
CM_Get_Child
CM_Get_DevNode_Registry_PropertyW
CompareDevGUIDs(&GUID_DEVCLASS_VOLUME)
CM_Get_DevNode_Registry_PropertyW
// Здесь проходим по всем буквам и сравниваем с registry_property
QueryDosDeviceW
SetupDiDestroyDeviceInfoList(hDevInfo);
.
.
.
Во первых, буквы бывают не только у томов (volumes), но и у разделов (partitions).
К примеру Flash диски, а именно removable устройства, не могут содержать более одного раздела, у них может напрочь отсуствовать таблица разделов. Если конкретнее, то томами управляет MountManger, а разделами ftdisk, ничего не знающий о томах но тем не менее управляющий разделами.
Если очень нужно, то букву можно назначить любому устройству вручную (программно), даже конкретно диску...
Но это так, предисловие...
Что касается Вашего вопроса по поводу буквы — укажите, какие данные у Вас есть (пример строки, структуры) по нужному стройству, а я попробую показать как это дело конвертнуть в букву.
Задачи получается две. Первая — получить список USB устройств, вторая — получить букву, если это диск.
Код ниже — не совсем то что требуется, но подкрутить не сложно. Подробности здесь, здесь и здесь.
Получить список устройств:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Panel1: TPanel;
rgDeviceType: TRadioGroup;
Button2: TButton;
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private{ Private declarations }public{ Public declarations }end;
var
Form1: TForm1;
implementation{$R *.dfm}Uses SetupApi;
procedure TForm1.Button2Click(Sender: TObject);
var
Guid : TGUID;
PnPHandle: HDevInfo;
DeviceInfoData : SP_DEVINFO_DATA;
DeviceInterfaceData: SP_DEVICE_INTERFACE_DATA;
i : Cardinal;
Success: LongBool;
DataT, buffersize: Cardinal;
buffer : PByte;
Const
DisplayGuid : TGUID = '{4d36e968-e325-11ce-bfc1-08002be10318}';
HidGuid : TGUID = '{745a17a0-74d3-11d0-b6fe-00a0c90f57da}';
USBGuid : TGUID = '{36FC9E60-C465-11CF-8056-444553540000}';
begin
ListBox1.Clear;
If rgDeviceType.ItemIndex = 0 then begin// Все устройства
PnPHandle:= SetupDiGetClassDevs(nil, nil, 0, DIGCF_PRESENT or DIGCF_ALLCLASSES);
End else begin
Case rgDeviceType.ItemIndex of
1: Guid:= DisplayGuid; // Все видеоадаптеры
2: Guid:= USBGuid; // Все USB-устройства
3: Guid:= HidGuid; // Все HID-устройстваEnd;
PnPHandle:= SetupDiGetClassDevs(@Guid, nil, 0, DIGCF_PRESENT);
End;
Try
i:= 0;
DeviceInfoData.cbSize:= SizeOf(SP_DEVINFO_DATA);
DeviceInterfaceData.cbSize := SizeOf(SP_DEVICE_INTERFACE_DATA);
Repeat
Success:= SetupDiEnumDeviceInfo(PnPHandle, i, DeviceInfoData);
If Success then begin
buffer:= nil;
buffersize:= 0;
while not SetupDiGetDeviceRegistryProperty
(
PnPHandle,
DeviceInfoData,
SPDRP_DEVICEDESC,
DataT,
buffer,
buffersize,
buffersize
)
do begin
if (GetLastError() = ERROR_INSUFFICIENT_BUFFER) then begin
if (buffer <> nil) then FreeMem(buffer);
buffer:= AllocMem(buffersize);
end else begin
break;
end;
end;
ListBox1.Items.Add(Format('%d: %s',[i, StrPas(PChar(buffer))]));
if (buffer <> nil) then FreeMem(buffer);
End;
Inc(i);
Application.ProcessMessages;
until not Success;
Finally
SetupDiDestroyDeviceInfoList(PnPHandle);
End;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin// если используется динамическая загрузка библиотеки
// LoadSetupApi;end;
procedure TForm1.FormDestroy(Sender: TObject);
begin// если используется динамическая загрузка библиотеки
// UnloadSetupApi;end;
end.
Работа с DOS-именами (правда здесь нет нужной задачи — по NT-имени, найти DOS-имя, но есть обратная и перечисление всех имен, думаю можно легко сделать обратно):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtCtrls;
type
TForm1 = class(TForm)
StatusBar: TStatusBar;
lbNameList: TListBox;
Panel1: TPanel;
Label1: TLabel;
Label2: TLabel;
NTDeviceName: TEdit;
DOSDeviceName: TEdit;
btnGetName: TButton;
btnAddName: TButton;
btnDelName: TButton;
btnGetList: TButton;
procedure btnGetNameClick(Sender: TObject);
procedure btnAddNameClick(Sender: TObject);
procedure btnDelNameClick(Sender: TObject);
procedure btnGetListClick(Sender: TObject);
procedure lbNameListDblClick(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation{$R *.dfm}
{Получение NT-имени по DOS-имени}procedure TForm1.btnGetNameClick(Sender: TObject);
Var Result : Array [1..MAX_PATH] of Char;
begin
If (QueryDosDevice(PChar(DOSDeviceName.Text), @Result, MAX_PATH) <> 0) then
NtDeviceName.Text:= StrPas(@Result)
Else
NtDeviceName.Text:= 'Устройство не существует';
end;
{Добавить DOS-имя для NT-имени}procedure TForm1.btnAddNameClick(Sender: TObject);
begin
If not DefineDosDevice(
DDD_RAW_TARGET_PATH,
PChar(DosDeviceName.Text),
PChar(NtDeviceName.Text))
then
StatusBar.Panels[0].Text:= 'Ошибка добавления имени';
end;
{Удалить DOS-имя}procedure TForm1.btnDelNameClick(Sender: TObject);
Var Result : Array [1..MAX_PATH] of Char;
begin{Ищем NT-имя для удаляемого DOS-имени}If not(QueryDosDevice(PChar(DOSDeviceName.Text), @Result, MAX_PATH) <> 0) then begin
StatusBar.Panels[0].Text:= 'DOS-имя не определено';
Exit;
End;
{Удаляем DOS-имя}If not DefineDosDevice(
DDD_RAW_TARGET_PATH or DDD_REMOVE_DEFINITION or DDD_EXACT_MATCH_ON_REMOVE,
PChar(DosDeviceName.Text),
PChar(NtDeviceName.Text)
) then
StatusBar.Panels[0].Text:= 'Ошибка удаления имени';
end;
{Получение всех имен устройства}procedure TForm1.btnGetListClick(Sender: TObject);
var BufSize : Cardinal; P, PName : Pointer; SName : String;
begin{Очищаем предыдущий список}
lbNameList.Items.Clear;
{Размер буфера}
BufSize:= 10240;
{Распределяем память для буфера}
GetMem(P, BufSize);
{Запрашиваем список имен}If QueryDosDevice(nil, P, BufSize) <> 0 then begin{Цикл по всем именам...}
PName:= P;
While (True) do begin
SName:= StrPas(PName);
If SName = ''then Break;
{Добавляем в список}
lbNameList.Items.Add(SName);
{Переход к следующему устройству}
{Сдвигаем указатель на следующую строку}
PName:= Pointer(LongInt(PName) + Length(SName)+1);
End;
End;
{Освобождаем буфер}
FreeMem(P);
end;
{Сортировка списка по двойному щелчку}procedure TForm1.lbNameListDblClick(Sender: TObject);
begin
lbNameList.Sorted:= True;
lbNameList.Sorted:= False;
end;
end.
Например, первая программа обнаружила устройство с именем
P>Устройство уже подключено, итерируя P>с помощью SetupDiХХХ нахожу все класса DiskDrive. P>как теперь найти их буквы?
Том может иметь от 0 до одной одной буквы и несколько mount_points.
Т.е. любой том (в том числе и на USB flash) может не иметь буквы, а только mount_point.
Номера дисков, на которых расположен том можно получить из volume extents.
Может этот пример поможет:
////////////////////////////////////////////////////////////////
// June of 2006.
// If this code works, it was written by Alexander Mamaev
// If not, I don't know who wrote it.
//
// This file contains example of using the following functions:
// - QueryDosDevice
// - FindFirstVolume/FindNextVolume/FindVolumeClose
// - FindFirstVolumeMountPoint/FindNextVolumeMountPoint/FindVolumeMountPointClose
////////////////////////////////////////////////////////////////#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#define ARRSIZE(x) (sizeof(x)/sizeof(x[0]))
///////////////////////////////////////////////////////////
// GetVolumeDosDevice
//
// Returns drive letter for given volume
// or '*' if no drive letter
///////////////////////////////////////////////////////////static WCHAR
GetVolumeDosDevice(
IN PCWSTR Volume
)
{
WCHAR buffer1[100];
WCHAR buffer2[100];
WCHAR Let[3];
if ( '\\' == Volume[0]
&& '\\' == Volume[1]
&& '?' == Volume[2]
&& '\\' == Volume[3]
&& QueryDosDeviceW( Volume + 4, buffer2, ARRSIZE(buffer2) ) )
{
Volume = buffer2;
}
for ( Let[0] = 'A', Let[1] = ':', Let[2] = 0; Let[0] <= L'Z'; Let[0] += 1 )
{
if ( QueryDosDeviceW( Let, buffer1, ARRSIZE(buffer1) )
&& 0 == _wcsicmp(buffer1, Volume) )
{
return Let[0];
}
}
return'*';
}
static const WCHAR szDriveTypes[][10]={
L"Unknown",
L"NoRoot",
L"Removable",
L"Fixed",
L"Remote",
L"CdRom",
L"RamDisk"
};
//
// Be sure that array szDriveType corresponds DRIVE_XXX constants
//
C_ASSERT( 0 == DRIVE_UNKNOWN );
C_ASSERT( 1 == DRIVE_NO_ROOT_DIR );
C_ASSERT( 2 == DRIVE_REMOVABLE );
C_ASSERT( 3 == DRIVE_FIXED );
C_ASSERT( 4 == DRIVE_REMOTE );
C_ASSERT( 5 == DRIVE_CDROM );
C_ASSERT( 6 == DRIVE_RAMDISK );
C_ASSERT( 7 == ARRSIZE(szDriveTypes) );
///////////////////////////////////////////////////////////
// program entry point
//
///////////////////////////////////////////////////////////int
main(
IN int argc,
IN char **argv
)
{
WCHAR szVolume[100];
VOLUME_DISK_EXTENTS* VolumeExtents = (VOLUME_DISK_EXTENTS*)_alloca( 512 );
HANDLE f;
UNREFERENCED_PARAMETER( argc );
UNREFERENCED_PARAMETER( argv );
//
// Do not show error when there is no media in floppy drive
//
SetErrorMode( SEM_FAILCRITICALERRORS );
//
// Enumerate volumes with FindFirstVolume/FindNextVolume/FindVolumeClose
//
f = FindFirstVolumeW( szVolume, ARRSIZE(szVolume) );
if ( INVALID_HANDLE_VALUE != f )
{
wprintf( L"\nVolumes:\n" );
do
{
UINT Len;
HANDLE h;
DWORD DriveType;
WCHAR szMountPoint[100];
WCHAR VolumeNameBuffer[64];
WCHAR FileSystemNameBuffer[64];
WCHAR DriveLetter;
//
// Get the length of volume to add/remove last slash
// FindFirstVolume/FindNextVolume always returns volume with last slash
//
Len = wcslen(szVolume);
if ( 0 == Len )
{
wprintf( L"Impossible!\n" );
continue;
}
wprintf( L"%s\n", szVolume );
//
// Get general volume information
//if ( GetVolumeInformationW( szVolume, VolumeNameBuffer, ARRSIZE(VolumeNameBuffer),
NULL, NULL, NULL,
FileSystemNameBuffer, ARRSIZE(FileSystemNameBuffer) ) )
{
wprintf( L" FileSystem : %s\n", FileSystemNameBuffer );
wprintf( L" Label : %s\n", VolumeNameBuffer );
}
//
// Get drive type (compare with IOCTL_DISK_GET_DRIVE_GEOMETRY)
//
DriveType = GetDriveTypeW( szVolume );
wprintf( L" DriveType : %s\n", szDriveTypes[DriveType >= ARRSIZE(szDriveTypes)? DRIVE_UNKNOWN : DriveType ] );
//
// Remove last slash
//
szVolume[Len-1] = 0;
//
// Get another name of volume
//
wprintf( L" Links : " );
if ( QueryDosDeviceW( szVolume + 4, szMountPoint, ARRSIZE(szMountPoint) ) )
wprintf( L" %s,", szMountPoint );
//
// Get drive letter
//
DriveLetter = GetVolumeDosDevice( szVolume );
wprintf( L" %c:\n", DriveLetter );
//
// Enumerate mount points (Last slash is required)
//
szVolume[Len-1] = '\\';
h = FindFirstVolumeMountPointW( szVolume, szMountPoint, ARRSIZE(szMountPoint) );
if ( INVALID_HANDLE_VALUE != h )
{
wprintf( L"This volume contains mount points:\n" );
do {
WCHAR szTmp[100];
//
// szMount point is root relative path. Create absolute path
//
_snwprintf( szTmp, ARRSIZE(szTmp), L"%c:\\%s", DriveLetter, szMountPoint );
szTmp[ARRSIZE(szTmp)-1] = 0;
if ( GetVolumeNameForVolumeMountPointW( szTmp, szMountPoint, ARRSIZE(szMountPoint) ) )
wprintf( L" %s => %s\n", szTmp, szMountPoint );
else
wprintf( L" %s => \"Unknown\"\n", szTmp );
} while( FindNextVolumeMountPointW( h, szMountPoint, ARRSIZE(szMountPoint) ) );
FindVolumeMountPointClose( h );
}
//
// Open volume to get usefull information (No last slash)
//
szVolume[Len-1] = 0;
h = CreateFileW( szVolume, MAXIMUM_ALLOWED,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( INVALID_HANDLE_VALUE != h )
{
DISK_GEOMETRY dg;
PARTITION_INFORMATION info;
GET_LENGTH_INFORMATION vlen;
DWORD i, Tmp;
//
// Get media type (compare with GetDriveTypeW)
//if ( DeviceIoControl( h, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg), &Tmp, NULL )
&& Tmp >= sizeof(dg) )
{
wprintf( L" Media type : %s\n", RemovableMedia == dg.MediaType
? L"Removable media other than floppy"
: FixedMedia == dg.MediaType
? L"Fixed hard disk"
: L"Unknown" );
}
//
// Get volume length (Requires Windows XP)
//if ( DeviceIoControl( h, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &vlen, sizeof(vlen), &Tmp, NULL )
&& Tmp >= sizeof(vlen) )
{
wprintf( L" Length : %lu.%02lu Gb\n",
(DWORD)(vlen.Length.QuadPart >> 30),
(DWORD)((((vlen.Length.QuadPart&0x3FFFFFFF) + 0x5FFFFF) * 100) >> 30) );
}
//
// Only for basic volumes
//if ( DeviceIoControl( h, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &info, sizeof(info), &Tmp, NULL )
&& Tmp >= sizeof(info) )
{
wprintf( L" Partition : type 0x%lx, number %lu, length %lu.%02lu Gb, boot \"%s\"\n",
(DWORD)info.PartitionType, info.PartitionNumber,
(DWORD)(info.PartitionLength.QuadPart >> 30),
(DWORD)((((info.PartitionLength.QuadPart&0x3FFFFFFF) + 0x5FFFFF) * 100) >> 30),
info.BootIndicator? L"yes" : L"no" );
}
//
// Get layout of volume
//if ( DeviceIoControl( h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, VolumeExtents, 512, &Tmp, NULL )
&& Tmp >= sizeof(*VolumeExtents) )
{
wprintf( L" Volume consists of %lu extent(s)\n", VolumeExtents->NumberOfDiskExtents );
for ( i = 0; i < VolumeExtents->NumberOfDiskExtents; i++ )
{
UINT64 Start = VolumeExtents->Extents[i].StartingOffset.QuadPart;
UINT64 End = VolumeExtents->Extents[i].StartingOffset.QuadPart + VolumeExtents->Extents[i].ExtentLength.QuadPart;
wprintf( L" %i: disk %lu, [0x%I64x 0x%I64x) bytes = [0x%lx 0x%lx) sectors\n", i,
VolumeExtents->Extents[i].DiskNumber,
Start, End, (DWORD)(Start>>9), (DWORD)(End>>9) );
}
}
CloseHandle( h );
}
wprintf( L"\n" );
} while ( FindNextVolumeW(f, szVolume, ARRSIZE(szVolume) ) );
FindVolumeClose( f );
}
//
// Exit to Windows
//return 0;
}
Здравствуйте, FoolS.Top, Вы писали:
FT>Здравствуйте, pullover, Вы писали:
P>>Устройство уже подключено, итерируя P>>с помощью SetupDiХХХ нахожу все класса DiskDrive. P>>как теперь найти их буквы?
FT>Приблизительно так
FT>
FT>.
FT>.
FT>.
FT>SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE,...
FT>SetupDiEnumDeviceInfo(hDevInfo, ...
FT>// Device class USB ?
FT>CM_Get_DevNode_Registry_PropertyW
FT>CompareDevGUIDs(&GUID_DEVCLASS_USB, ...);
FT>// Device class diskdrive ?
FT>CM_Get_Child
FT>CM_Get_DevNode_Registry_PropertyW
FT>CompareDevGUIDs(&GUID_DEVCLASS_DISKDRIVE, ...
FT>// Device class volume ?
FT>CM_Get_Child
FT>CM_Get_DevNode_Registry_PropertyW
FT>CompareDevGUIDs(&GUID_DEVCLASS_VOLUME)
FT>CM_Get_DevNode_Registry_PropertyW
FT>// Здесь проходим по всем буквам и сравниваем с registry_property
FT>QueryDosDeviceW
FT>SetupDiDestroyDeviceInfoList(hDevInfo);
FT>.
FT>.
FT>.
FT>
когда перечисляю USB — нахожу мой девайс по VID (0х058F):
\\?\usb#vid_058f&pid_9386#00000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
если идти с другой стороны и перечислять тома то все просто:
\\?\storage#removablemedia#8&d00109a&0&rm#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}\ ->
\\?\Volume{21ad27be-04e1-11db-994a-0013208178ff}\ ->
\Device\Harddisk1\DP(1)0-0+38 ->
G:
вопрос как связать
\\?\usb#vid_058f&pid_9386#00000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
с
\\?\storage#removablemedia#8&d00109a&0&rm#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}\
P>вопрос как связать P>\\?\usb#vid_058f&pid_9386#00000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed} P>с P>\\?\storage#removablemedia#8&d00109a&0&rm#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}\
P>????
\\?\storage#removablemedia#8&d00109a&0&rm#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
первый вызов CM_Get_Parent приведет вас к диску, второй от диска к вашему усб устройству
\\?\usb#vid_058f&pid_9386#00000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
разумеется это все образно выражаясь, так как оперировать вы будете нодами, а не интерфейсами. Ну а потом из нодов можно получить соотв интерфейсы. И еще один момент, это будет работать только для онлайн устройств, которые вставлены (DIGCF_PRESENT)
P>как из \\?\usb#vid_058f&pid_9386#00000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed} P>официально (без substr) найти vendor id девайса?
судя по всему только так, формат стандартный. Но выковиривать его правильнее не из интерфейса, а из hardware_id
usb\vid_058f&pid_9386
хотя по большому счету разницы нет, но формат символических ссылок не документирован
Здравствуйте, Alexey Frolov,
P>>как из \\?\usb#vid_058f&pid_9386#00000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed} P>>официально (без substr) найти vendor id девайса?
AF>судя по всему только так, формат стандартный. Но выковиривать его правильнее не из интерфейса, а из hardware_id AF>usb\vid_058f&pid_9386 AF>хотя по большому счету разницы нет, но формат символических ссылок не документирован
Не совсем в тему, но DDK\src\wdm\usb\usbview\ получает idVendor и прочее посредством IOCTL_USB_GET_NODE_CONNECTION_INFORMATION хабу.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, gear nuke, Вы писали:
GN>Не совсем в тему, но DDK\src\wdm\usb\usbview\ получает idVendor и прочее посредством IOCTL_USB_GET_NODE_CONNECTION_INFORMATION хабу.
Ну почему не в тему, вполне в тему, это я не подумав сразу сказал, виноват.
Вполне можно получить USB_DEVICE_DESCRIPTOR, который содержит idVendor
Последовательность такая, нужно отослать URB — usb request block посредством
IOCTL_INTERNAL_USB_SUBMIT_URB. URB следующего содержания
URB_CONTROL_DESCRIPTOR_REQUEST с функцией URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
DescriptorType = USB_DEVICE_DESCRIPTOR_TYPE, в ответ получите структуру USB_DEVICE_DESCRIPTOR, эта структура кстати содержится в упоминаемой вами USB_NODE_CONNECTION_INFORMATION_EX. Так что ваша правда. HardwareId строится как раз посредством этого запроса
Здравствуйте, Alexey Frolov, Вы писали:
AF>Ну почему не в тему, вполне в тему, это я не подумав сразу сказал, виноват.
Дык я имел ввиду посылку IOCTL устройству с симлинком вида \\?\usb#root_hub#4&293b228e&0#{f18a0e88-c30c-11d0-8815-00a0c906bed8} а не \\?\usb#vid_058f&pid_9386#00000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
AF>Вполне можно получить USB_DEVICE_DESCRIPTOR, который содержит idVendor AF>Последовательность такая, нужно отослать URB — usb request block посредством AF>IOCTL_INTERNAL_USB_SUBMIT_URB.
О, это драйвер нужен? Тот-то вариант из юзерленда делается, вот только не знаю, можно ли без энумерации хабов обойтись, а с ней кода на 2+ экрана
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth