Я написал программу на C, которая демонстрирует, как получать необходимую информацию
#include <windows.h>
#include <devguid.h> // for GUID_DEVCLASS_CDROM etc
#include <setupapi.h>
#include <cfgmgr32.h> // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID
#include <tchar.h>
#include <stdio.h>
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
#pragma comment (lib, "setupapi.lib")
//
// Define the various device characteristics flags (defined in wdm.h)
//
#define FILE_REMOVABLE_MEDIA 0x00000001
#define FILE_READ_ONLY_DEVICE 0x00000002
#define FILE_FLOPPY_DISKETTE 0x00000004
#define FILE_WRITE_ONCE_MEDIA 0x00000008
#define FILE_REMOTE_DEVICE 0x00000010
#define FILE_DEVICE_IS_MOUNTED 0x00000020
#define FILE_VIRTUAL_VOLUME 0x00000040
#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080
#define FILE_DEVICE_SECURE_OPEN 0x00000100
#define FILE_CHARACTERISTIC_PNP_DEVICE 0x00000800
#define FILE_CHARACTERISTIC_TS_DEVICE 0x00001000
#define FILE_CHARACTERISTIC_WEBDAV_DEVICE 0x00002000
#pragma warning (disable: 4201)
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
} DUMMYUNIONNAME;
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
#pragma warning (default: 4201)
typedef enum _FSINFOCLASS {
FileFsVolumeInformation = 1,
FileFsLabelInformation, // 2
FileFsSizeInformation, // 3
FileFsDeviceInformation, // 4
FileFsAttributeInformation, // 5
FileFsControlInformation, // 6
FileFsFullSizeInformation, // 7
FileFsObjectIdInformation, // 8
FileFsDriverPathInformation, // 9
FileFsVolumeFlagsInformation,// 10
FileFsMaximumInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
typedef struct _FILE_FS_DEVICE_INFORMATION {
DEVICE_TYPE DeviceType;
ULONG Characteristics;
} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;
typedef NTSTATUS (NTAPI *LPFN_NT_QUERY_VOLUME_INFORMATION_FILE) (HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FsInformation, ULONG Length,
FS_INFORMATION_CLASS FsInformationClass);
BOOL GetDriveTypeAndCharacteristics (HANDLE hDevice, DEVICE_TYPE *pDeviceType, ULONG *pCharacteristics)
{
HMODULE hNtDll;
LPFN_NT_QUERY_VOLUME_INFORMATION_FILE lpfnNtQueryVolumeInformationFile;
NTSTATUS ntStatus;
IO_STATUS_BLOCK IoStatusBlock;
FILE_FS_DEVICE_INFORMATION FileFsDeviceInfo;
BOOL bSuccess = FALSE;
hNtDll = GetModuleHandle (TEXT("ntdll.dll"));
if (hNtDll == NULL)
return FALSE;
lpfnNtQueryVolumeInformationFile = (LPFN_NT_QUERY_VOLUME_INFORMATION_FILE)GetProcAddress (hNtDll, "NtQueryVolumeInformationFile");
if (lpfnNtQueryVolumeInformationFile == NULL)
return FALSE;
ntStatus = lpfnNtQueryVolumeInformationFile (hDevice, &IoStatusBlock,
&FileFsDeviceInfo, sizeof(FileFsDeviceInfo),
FileFsDeviceInformation);
if (ntStatus == NO_ERROR) {
bSuccess = TRUE;
*pDeviceType = FileFsDeviceInfo.DeviceType;
*pCharacteristics = FileFsDeviceInfo.Characteristics;
}
return bSuccess;
}
void FildVolumeName (LPCTSTR pszDeviceName)
{
TCHAR szVolumeName[MAX_PATH] = TEXT("");
TCHAR szDeviceName[MAX_PATH] = TEXT("");
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwCharCount;
BOOL bSuccess;
hFind = FindFirstVolume (szVolumeName, ARRAYSIZE(szVolumeName));
if (hFind == INVALID_HANDLE_VALUE) return;
while(TRUE) {
// Skip the \\?\ prefix and remove the trailing backslash.
size_t Index = lstrlen(szVolumeName) - 1;
if (szVolumeName[0] != TEXT('\\') ||
szVolumeName[1] != TEXT('\\') ||
szVolumeName[2] != TEXT('?') ||
szVolumeName[3] != TEXT('\\') ||
szVolumeName[Index] != TEXT('\\')) return; // error
// QueryDosDeviceW doesn't allow a trailing backslash,
// so temporarily remove it.
szVolumeName[Index] = TEXT('\0');
dwCharCount = QueryDosDevice (&szVolumeName[4], szDeviceName, ARRAYSIZE(szDeviceName));
szVolumeName[Index] = TEXT('\\');
if (dwCharCount == 0) return; // error
if (lstrcmp (pszDeviceName, szDeviceName) == 0) {
_tprintf (TEXT(" Volume Device Name: %s\n"), szVolumeName);
return;
}
bSuccess = FindNextVolume (hFind, szVolumeName, ARRAYSIZE(szVolumeName));
if (!bSuccess) {
DWORD dwErrorCode = GetLastError();
if (dwErrorCode == ERROR_NO_MORE_ITEMS)
break;
else
break; // ERROR!!!
}
}
}
void DumpVidPidMi (LPCTSTR pszDeviceInstanceId)
{
TCHAR szDeviceInstanceId[MAX_DEVICE_ID_LEN];
const static LPCTSTR arPrefix[3] = {TEXT("VID_"), TEXT("PID_"), TEXT("MI_")};
LPTSTR pszToken, pszNextToken;
int j;
lstrcpy (szDeviceInstanceId, pszDeviceInstanceId);
pszToken = _tcstok_s (szDeviceInstanceId , TEXT("\\#&"), &pszNextToken);
while(pszToken != NULL) {
for (j = 0; j < 3; j++) {
if (_tcsncmp(pszToken, arPrefix[j], lstrlen(arPrefix[j])) == 0) {
switch(j) {
case 0:
_tprintf (TEXT(" vid: \"%s\"\n"), pszToken + lstrlen(arPrefix[j]));
break;
case 1:
_tprintf (TEXT(" pid: \"%s\"\n"), pszToken + lstrlen(arPrefix[j]));
break;
case 2:
_tprintf (TEXT(" mi: \"%s\"\n"), pszToken + lstrlen(arPrefix[j]));
break;
default:
break;
}
}
}
pszToken = _tcstok_s (NULL, TEXT("\\#&"), &pszNextToken);
}
}
BOOL FindDiInfos (LPCGUID pGuidInferface, LPCGUID pGuidClass, LPCTSTR pszEnumerator,
DEVICE_TYPE DeviceType, DWORD DeviceNumber,
DWORD dwDeviceInstanceIdSize, // MAX_DEVICE_ID_LEN
OUT LPTSTR pszDeviceInstanceId,
OUT PDWORD pdwRemovalPolicy)
//#define CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL 1
//#define CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL 2
//#define CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL 3
{
HDEVINFO hIntDevInfo = NULL;
DWORD dwIndex;
BOOL bFound = FALSE;
HANDLE hDev = INVALID_HANDLE_VALUE;
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;
// set defaults
*pdwRemovalPolicy = 0;
pszDeviceInstanceId[0] = TEXT('\0');
__try {
hIntDevInfo = SetupDiGetClassDevs (pGuidInferface, pszEnumerator, NULL,
pGuidInferface != NULL? DIGCF_PRESENT | DIGCF_DEVICEINTERFACE:
DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hIntDevInfo == INVALID_HANDLE_VALUE)
__leave;
for (dwIndex = 0; ;dwIndex ++) {
SP_DEVICE_INTERFACE_DATA interfaceData;
SP_DEVINFO_DATA deviceInfoData;
DWORD dwDataType, dwRequiredSize;
BOOL bSuccess;
ZeroMemory (&interfaceData, sizeof(interfaceData));
interfaceData.cbSize = sizeof(interfaceData);
bSuccess = SetupDiEnumDeviceInterfaces (hIntDevInfo, NULL, pGuidInferface, dwIndex, &interfaceData);
if (!bSuccess) {
DWORD dwErrorCode = GetLastError();
if (dwErrorCode == ERROR_NO_MORE_ITEMS)
break;
else
break; // ERROR!!!
}
dwRequiredSize = 0;
bSuccess = SetupDiGetDeviceInterfaceDetail (hIntDevInfo, &interfaceData, NULL, 0, &dwRequiredSize, NULL);
if ((!bSuccess && GetLastError() != ERROR_INSUFFICIENT_BUFFER) || dwRequiredSize == 0)
continue; // ERROR!!!
if (pInterfaceDetailData)
pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalFree (pInterfaceDetailData);
pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc (LPTR, dwRequiredSize);
pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
ZeroMemory (&deviceInfoData, sizeof(deviceInfoData));
deviceInfoData.cbSize = sizeof(deviceInfoData);
bSuccess = SetupDiGetDeviceInterfaceDetail (hIntDevInfo, &interfaceData,
pInterfaceDetailData, dwRequiredSize, &dwRequiredSize, &deviceInfoData);
if (!bSuccess)
continue;
hDev = CreateFile (pInterfaceDetailData->DevicePath,
0, // no access to the drive
FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL); // do not copy file attributes
if (hDev != INVALID_HANDLE_VALUE) {
STORAGE_DEVICE_NUMBER sdn;
DWORD cbBytesReturned;
bSuccess = DeviceIoControl (hDev, // device to be queried
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, // no input buffer
(LPVOID)&sdn, sizeof(sdn), // output buffer
&cbBytesReturned, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O
if (bSuccess) {
if (sdn.DeviceType == DeviceType &&
sdn.DeviceNumber == DeviceNumber) {
DEVINST dnDevInstParent, dnDevInstParentParent;
CONFIGRET ret;
// device found !!!
TCHAR szBuffer[4096];
_tprintf (TEXT(" DevicePath: %s\n"), pInterfaceDetailData->DevicePath);
bSuccess = SetupDiGetDeviceInstanceId (hIntDevInfo, &deviceInfoData, pszDeviceInstanceId,
dwDeviceInstanceIdSize, &dwRequiredSize);
if (dwRequiredSize > MAX_DEVICE_ID_LEN)
continue;
bSuccess = SetupDiGetDeviceRegistryProperty (hIntDevInfo, &deviceInfoData, SPDRP_REMOVAL_POLICY, &dwDataType,
(PBYTE)pdwRemovalPolicy, sizeof(DWORD), &dwRequiredSize);
// SPDRP_CHARACTERISTICS - Device characteristics
// FILE_FLOPPY_DISKETTE, FILE_REMOVABLE_MEDIA, and FILE_WRITE_ONCE_MEDIA characteristics
// FILE_READ_ONLY_DEVICE
bSuccess = SetupDiGetDeviceRegistryProperty (hIntDevInfo, &deviceInfoData, SPDRP_CLASS, &dwDataType,
(PBYTE)szBuffer, sizeof(szBuffer), &dwRequiredSize);
if (bSuccess)
_tprintf (TEXT(" Class: \"%s\"\n"), szBuffer);
bSuccess = SetupDiGetDeviceRegistryProperty (hIntDevInfo, &deviceInfoData, SPDRP_HARDWAREID, &dwDataType,
(PBYTE)szBuffer, sizeof(szBuffer), &dwRequiredSize);
if (bSuccess) {
LPCTSTR pszId;
_tprintf (TEXT(" Hardware IDs:\n"));
for (pszId=szBuffer;
*pszId != TEXT('\0') && pszId + dwRequiredSize/sizeof(TCHAR) <= szBuffer + ARRAYSIZE(szBuffer);
pszId += lstrlen(pszId)+1) {
_tprintf (TEXT(" \"%s\"\n"), pszId);
}
}
bSuccess = SetupDiGetDeviceRegistryProperty (hIntDevInfo, &deviceInfoData, SPDRP_FRIENDLYNAME, &dwDataType,
(PBYTE)szBuffer, sizeof(szBuffer), &dwRequiredSize);
if (bSuccess)
_tprintf (TEXT(" Friendly Name: \"%s\"\n"), szBuffer);
bSuccess = SetupDiGetDeviceRegistryProperty (hIntDevInfo, &deviceInfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, &dwDataType,
(PBYTE)szBuffer, sizeof(szBuffer), &dwRequiredSize);
if (bSuccess)
_tprintf (TEXT(" Physical Device Object Name: \"%s\"\n"), szBuffer);
bSuccess = SetupDiGetDeviceRegistryProperty (hIntDevInfo, &deviceInfoData, SPDRP_DEVICEDESC, &dwDataType,
(PBYTE)szBuffer, sizeof(szBuffer), &dwRequiredSize);
if (bSuccess)
_tprintf (TEXT(" Device Description: \"%s\"\n"), szBuffer);
bFound = TRUE;
ret = CM_Get_Parent (&dnDevInstParent, deviceInfoData.DevInst, 0);
if (ret == CR_SUCCESS) {
TCHAR szDeviceInstanceID[MAX_DEVICE_ID_LEN];
ret = CM_Get_Device_ID (dnDevInstParent, szDeviceInstanceID, ARRAY_SIZE(szDeviceInstanceID), 0);
if (ret == CR_SUCCESS) {
_tprintf (TEXT(" Parent Device Instance ID: %s\n"), szDeviceInstanceID);
DumpVidPidMi (szDeviceInstanceID);
ret = CM_Get_Parent (&dnDevInstParentParent, dnDevInstParent, 0);
if (ret == CR_SUCCESS) {
ret = CM_Get_Device_ID (dnDevInstParentParent, szDeviceInstanceID, ARRAY_SIZE(szDeviceInstanceID), 0);
if (ret == CR_SUCCESS)
_tprintf (TEXT(" Parent of Parent Device Instance ID: %s\n"), szDeviceInstanceID);
}
}
}
break;
}
}
CloseHandle (hDev);
hDev = INVALID_HANDLE_VALUE;
}
}
}
__finally {
if (pInterfaceDetailData)
pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalFree (pInterfaceDetailData);
if (hDev != INVALID_HANDLE_VALUE)
CloseHandle (hDev);
if (hIntDevInfo)
SetupDiDestroyDeviceInfoList (hIntDevInfo);
}
return bFound;
}
LPCTSTR DumpBusTypeAsString (STORAGE_BUS_TYPE type)
{
const static LPCTSTR arStorageBusTypeNames[] = {
TEXT("Unknown"), // BusTypeUnknown = 0
TEXT("SCSI"), // BusTypeScsi = 1
TEXT("ATAPI"), // BusTypeAtapi = 2
TEXT("ATA"), // BusTypeAta = 3
TEXT("IEEE-1394"), // BusType1394 = 4
TEXT("SSA"), // BusTypeSsa = 5
TEXT("Fibre Channel"), // BusTypeFibre = 6
TEXT("USB"), // BusTypeUsb = 7
TEXT("RAID"), // BusTypeRAID = 8
TEXT("iSCSI"), // BusTypeiScsi = 9
TEXT("Serial Attached SCSI (SAS)"), // BusTypeSas = 10
TEXT("SATA"), // BusTypeSata = 11
TEXT("SD"), // BusTypeSd = 12
TEXT("MMC"), // BusTypeMmc = 13
TEXT("Virtual"), // BusTypeVirtual = 14
TEXT("FileBackedVirtual") // BusTypeFileBackedVirtual = 15
};
if (type <= BusTypeFileBackedVirtual)
return arStorageBusTypeNames[type];
else
return NULL;
}
int main()
{
HANDLE hDevice;
DWORD cbBytesReturned;
STORAGE_DEVICE_NUMBER sdn;
BOOL bSuccess;
LPTSTR pszLogicalDrives, pszDriveRoot;
TCHAR szDeviceInstanceId[MAX_DEVICE_ID_LEN];
GUID *pGuidInferface = NULL, *pGuidClass = NULL;
LPCTSTR pszEnumerator = NULL;
TCHAR szVolumeName[MAX_PATH+1], szFileSystemName[MAX_PATH+1], szNtDeviceName[MAX_PATH+1];
//TCHAR szVolumeSerialNumber[1024];
DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
//HMODULE hm = LoadLibrary (TEXT("C:\\Program Files\\Microsoft Office\\Office14\\OUTLOOK.EXE"));
__try {
//pszEnumerator = TEXT("USB");
cbBytesReturned = GetLogicalDriveStrings (0, NULL);
pszLogicalDrives = (LPTSTR) LocalAlloc (LMEM_ZEROINIT,
cbBytesReturned*sizeof(TCHAR));
cbBytesReturned = GetLogicalDriveStrings (cbBytesReturned,
pszLogicalDrives);
for (pszDriveRoot = pszLogicalDrives; *pszDriveRoot != TEXT('\0');
pszDriveRoot += lstrlen(pszDriveRoot) + 1) {
TCHAR szDeviceName[7] = TEXT("\\\\.\\");
BOOL bIsRemoveable = FALSE;
DWORD dwRemovalPolicy;
STORAGE_PROPERTY_QUERY spq;
BYTE byBuffer[4096];
//ULONG ulOutBuffer;
szDeviceName[4] = pszDriveRoot[0];
szDeviceName[5] = TEXT(':');
szDeviceName[6] = TEXT('\0');
_tprintf (TEXT("Drive %c:\n"), pszDriveRoot[0]);
// see http://msdn.microsoft.com/en-us/library/cc542456.aspx
// how to find Volume name: \\?\Volume{4c1b02c1-d990-11dc-99ae-806e6f6e6963}\
// for the Paths: C:\
// or device name like \Device\HarddiskVolume2 or \Device\CdRom0
cbBytesReturned = QueryDosDevice (&szDeviceName[4], szNtDeviceName, ARRAYSIZE(szNtDeviceName));
if (cbBytesReturned) {
_tprintf (TEXT(" Dos Device Name: %s\n"), szNtDeviceName);
FildVolumeName(szNtDeviceName);
}
bSuccess = GetVolumeInformation (pszDriveRoot, szVolumeName, ARRAYSIZE(szVolumeName),
&dwVolumeSerialNumber, &dwMaximumComponentLength, &dwFileSystemFlags,
szFileSystemName, ARRAYSIZE(szFileSystemName));
if (bSuccess) {
_tprintf (TEXT(" Volume Name: \"%s\"\n"), szVolumeName);
}
hDevice = CreateFile (szDeviceName,
//FILE_READ_DATA, //0 - no access to the drive, for IOCTL_STORAGE_CHECK_VERIFY is FILE_READ_DATA needed
FILE_READ_ATTRIBUTES, // for IOCTL_STORAGE_CHECK_VERIFY2
FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
__leave;
bIsRemoveable = FALSE;
spq.PropertyId = StorageDeviceProperty;
spq.QueryType = PropertyStandardQuery;
spq.AdditionalParameters[0] = 0;
bSuccess = DeviceIoControl (hDevice, // device to be queried
IOCTL_STORAGE_QUERY_PROPERTY, // operation to perform
&spq, sizeof(spq), // input buffer
&byBuffer, sizeof(byBuffer), // output buffer
&cbBytesReturned, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O
if (bSuccess) {
STORAGE_DEVICE_DESCRIPTOR *psdp = (STORAGE_DEVICE_DESCRIPTOR *)byBuffer;
LPCTSTR pszBusType = DumpBusTypeAsString(psdp->BusType);
if (pszBusType)
_tprintf (TEXT(" Bus Type: %s\n"), pszBusType);
else
_tprintf (TEXT(" Bus Type: Unknown (%d)\n"), psdp->BusType);
if (psdp->VendorIdOffset)
_tprintf (TEXT(" VendorId: \"%hs\"\n"), (LPCSTR)((PBYTE)psdp + psdp->VendorIdOffset));
if (psdp->ProductIdOffset)
_tprintf (TEXT(" ProductId: \"%hs\"\n"), (LPCSTR)((PBYTE)psdp + psdp->ProductIdOffset));
if (psdp->ProductRevisionOffset)
_tprintf (TEXT(" ProductRevision: \"%hs\"\n"), (LPCSTR)((PBYTE)psdp + psdp->ProductRevisionOffset));
if (psdp->RemovableMedia)
bIsRemoveable = TRUE;
}
cbBytesReturned = 0;
bSuccess = DeviceIoControl (hDevice, // device to be queried
IOCTL_STORAGE_CHECK_VERIFY2,
NULL, 0, // no input buffer
NULL, 0, // no output buffer
&cbBytesReturned, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O
if (bSuccess)
_tprintf (TEXT(" the device media are accessible\n"));
else if (GetLastError() == ERROR_NOT_READY)
_tprintf (TEXT(" the device media are not accessible\n"));
bSuccess = DeviceIoControl (hDevice, // device to be queried
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, // no input buffer
(LPVOID)&sdn, sizeof(sdn), // output buffer
&cbBytesReturned, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O
// GetLastError of ERROR_MORE_DATA indicates to the caller that the buffer was not large enough to accommodate the data requested
if (!bSuccess) __leave;
_tprintf (TEXT(" DeviceType: %d, DeviceNumber: %d, PartitionNumber: %d\n"), sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber);
pGuidInferface = NULL;
pGuidClass = NULL;
if (sdn.DeviceType == FILE_DEVICE_CD_ROM || sdn.DeviceType == FILE_DEVICE_DVD) {
pGuidInferface = (GUID*)&GUID_DEVINTERFACE_CDROM;
pGuidClass = (GUID*)&GUID_DEVCLASS_CDROM;
}
else if (sdn.DeviceType == FILE_DEVICE_DISK) {
DEVICE_TYPE DeviceType;
ULONG ulCharacteristics;
bSuccess = GetDriveTypeAndCharacteristics (hDevice, &DeviceType, &ulCharacteristics);
if (bSuccess) {
if ((ulCharacteristics & FILE_FLOPPY_DISKETTE) == FILE_FLOPPY_DISKETTE) {
pGuidInferface = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
pGuidClass = (GUID*)&GUID_DEVCLASS_FLOPPYDISK;
}
else {
pGuidInferface = (GUID*)&GUID_DEVINTERFACE_DISK;
pGuidClass = (GUID*)&GUID_DEVCLASS_DISKDRIVE;
}
if ((ulCharacteristics & FILE_REMOVABLE_MEDIA) == FILE_REMOVABLE_MEDIA)
bIsRemoveable = TRUE;
}
}
// GUID_DEVCLASS_MEDIUM_CHANGER
if (CloseHandle (hDevice))
hDevice = INVALID_HANDLE_VALUE;
bSuccess = FindDiInfos (pGuidInferface, pGuidClass, pszEnumerator, sdn.DeviceType, sdn.DeviceNumber,
ARRAY_SIZE(szDeviceInstanceId), // MAX_DEVICE_ID_LEN
szDeviceInstanceId,
&dwRemovalPolicy);
if (bSuccess) {
if (dwRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL ||
dwRemovalPolicy == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL)
bIsRemoveable = TRUE;
_tprintf (TEXT(" DeviceInstanceId: %s\n"), szDeviceInstanceId);
if (bIsRemoveable)
_tprintf (TEXT(" Drive %c: is removeable\n"), pszDriveRoot[0]);
}
}
}
__finally {
if (pszLogicalDrives)
pszLogicalDrives = (LPTSTR) LocalFree (pszLogicalDrives);
if (hDevice != INVALID_HANDLE_VALUE)
bSuccess = CloseHandle (hDevice);
}
return 0;
}
Программа может быть скомпилирована без установленного Windows DDK (только Windows SDK, который установлен, например, вместе с Visual Studioнеобходимо).Программа производит вывод, подобный следующему:
....
Drive L:
Dos Device Name: \Device\CdRom2
Volume Device Name: \\?\Volume{2c5f6a93-2b50-11df-aa6a-005056c00008}\
Volume Name: "SONYPICTUTIL"
Bus Type: USB
VendorId: "HL-DT-ST"
ProductId: "DVDRAM GE20LU11 "
ProductRevision: "CL01"
the device media are accessible
DeviceType: 2, DeviceNumber: 2, PartitionNumber: -1
DevicePath: \\?\usbstor#cdrom&ven_hl-dt-st&prod_dvdram_ge20lu11&rev_cl01#0010101640008b615&0#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}
Class: "CDROM"
Hardware IDs:
"USBSTOR\CdRomHL-DT-STDVDRAM_GE20LU11_CL01"
"USBSTOR\CdRomHL-DT-STDVDRAM_GE20LU11_"
"USBSTOR\CdRomHL-DT-ST"
"USBSTOR\HL-DT-STDVDRAM_GE20LU11_C"
"HL-DT-STDVDRAM_GE20LU11_C"
"USBSTOR\GenCdRom"
"GenCdRom"
Friendly Name: "HL-DT-ST DVDRAM GE20LU11 USB Device"
Physical Device Object Name: "\Device\00000096"
Device Description: "CD-ROM Drive"
Parent Device Instance ID: USB\VID_152E&PID_1640\0010101640008B615
vid: "152E"
pid: "1640"
Parent of Parent Device Instance ID: USB\ROOT_HUB20\4&29A1BD9B&0
DeviceInstanceId: USBSTOR\CDROM&VEN_HL-DT-ST&PROD_DVDRAM_GE20LU11&REV_CL01\0010101640008B615&0
Drive L: is removeable
Drive N:
Dos Device Name: \Device\HarddiskVolume8
Volume Device Name: \\?\Volume{ae08a3c8-71cf-11de-bc1d-005056c00008}\
Volume Name: ""
Bus Type: USB
VendorId: "SanDisk "
ProductId: "Cruzer "
ProductRevision: "8.01"
the device media are accessible
DeviceType: 7, DeviceNumber: 5, PartitionNumber: 1
DevicePath: \\?\usbstor#disk&ven_sandisk&prod_cruzer&rev_8.01#1740030578903736&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
Class: "DiskDrive"
Hardware IDs:
"USBSTOR\DiskSanDisk_Cruzer__________8.01"
"USBSTOR\DiskSanDisk_Cruzer__________"
"USBSTOR\DiskSanDisk_"
"USBSTOR\SanDisk_Cruzer__________8"
"SanDisk_Cruzer__________8"
"USBSTOR\GenDisk"
"GenDisk"
Friendly Name: "SanDisk Cruzer USB Device"
Physical Device Object Name: "\Device\000000aa"
Device Description: "Disk drive"
Parent Device Instance ID: USB\VID_0781&PID_5406\1740030578903736
vid: "0781"
pid: "5406"
Parent of Parent Device Instance ID: USB\ROOT_HUB20\4&128079C2&0
DeviceInstanceId: USBSTOR\DISK&VEN_SANDISK&PROD_CRUZER&REV_8.01\1740030578903736&0
Drive N: is removeable
Поскольку нас интересуют только устройства, доступные через буквы дисков, программа начинается с перечисления всех логических дисков в системе с учетом функции GetLogicalDriveStrings
.Для каждого диска мы можем использовать IOCTL_STORAGE_QUERY_PROPERTY
для получения информации, такой как VendorId
, ProductId
и ProductRevision
.Использование IOCTL_STORAGE_GET_DEVICE_NUMBER
позволяет нам получить тип привода (например, CD / DVD или Disk / Floppy).Более того, два числа: DeviceType
и DeviceNumber
являются уникальными в системе, и мы можем использовать их в качестве основы для точной настройки экземпляра устройства (используя SetupDi
- функции) для привода.
Поскольку устройства Floppy и Disk имеют одинаковый тип определения FILE_DEVICE_DISK
Я демонстрирую другую функцию NtQueryVolumeInformationFile
с параметром FileFsDeviceInformation
, чтобы получить так называемое Характеристики для устройства.Эта характеристика - лучший способ удалить дискету с других дисков и выбрать соответствующий класс и интерфейс GUID для перечисления устройства (GUID_DEVINTERFACE_FLOPPY
или GUID_DEVINTERFACE_DISK
).Мы получаем DeviceType и DeviceNumber для всех устройств, перечисленных с учетом SetupDi
API.По тому, как мы узнаем, какое устройство имеет какую букву диска.
Еще одна важная вещь - это иерархия устройств: отношения родитель / потомок.Чтобы продемонстрировать это, я использую функции CM_Get_Parent
и CM_Get_Device_ID
в примере кода.Таким образом, мы можем видеть, какое устройство USB имеет какое устройство хранения в качестве дочернего.
Я отобразил некоторую информацию о найденных устройствах.Вы можете комбинировать API из примера с IOCTL_MOUNTMGR_QUERY_POINTS
(см. Использование IOCTL_MOUNTMGR_QUERY_POINTS ) или FindFirstVolumeW
, FindNextVolumeW
и GetVolumePathNamesForVolumeNameW
(см. http://msdn.microsoft.com/en-us/library/cc542456(VS.85).aspx) для получения более подробной информации, если это необходимо.
ОБНОВЛЕНО : Кстати, буфер, возвращаемый IOCTL_STORAGE_QUERY_PROPERTY
, имеет другие поля, такие как STORAGE_BUS_TYPE BusType
(BusTypeUsb
, BusTypeFibre
, BusTypeSd
и т. Д.) И т. Д.также используйте IOCTL_STORAGE_QUERY_PROPERTY
, чтобы запросить другую информацию, такую как StorageDeviceUniqueIdProperty
или StorageDeviceUniqueIdProperty
и т. д. Если вы хотите иметь больше информации, специфичной для USB, я рекомендую вам http://www.emmet -gray.com / Articles / USB_SerialNumbers.htm который показывает использование IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX
, IOCTL_USB_GET_NODE_INFORMATION
и IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
.
ОБНОВЛЕНО 2: Я поместил расширенную версию программы в http://www.ok -soft-gmbh.com/ForStackOverflow/EnumMassStorage.c из-за ограничения размером сообщения в stackoverflow.com. Результат теста выглядит следующим образом: http://www.ok -soft-gmbh.com / ForStackOverflow / EnumMassStorage.txt
ОБНОВЛЕНО 3: Я нашел ошибку и обновил код. Пожалуйста, используйтепоследнюю версию кода и убедитесь, что ваша проблема решена.