at first we need enumerate all disks in system by call CM_Get_Device_Interface_ListW
and CM_Get_Device_Interface_List_SizeW
with GUID_DEVINTERFACE_DISK
#include <Shlwapi.h>
#include <cfgmgr32.h>
#undef _NTDDSTOR_H_
#include <ntddstor.h>
#include <ntdddisk.h>
static volatile UCHAR guz;
CONFIGRET EnumDisks(PCSTR prefix, PGUID InterfaceClassGuid)
{
CONFIGRET err;
PVOID stack = alloca(guz);
ULONG BufferLen = 0, NeedLen = 256;
union {
PVOID buf;
PWSTR pszDeviceInterface;
};
for(;;)
{
if (BufferLen < NeedLen)
{
BufferLen = RtlPointerToOffset(buf = alloca((NeedLen - BufferLen) * sizeof(WCHAR)), stack) / sizeof(WCHAR);
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid,
0, pszDeviceInterface, BufferLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
if (err = CM_Get_Device_Interface_List_SizeW(&NeedLen, InterfaceClassGuid,
0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
default:
return err;
}
continue;
case CR_SUCCESS:
while (*pszDeviceInterface)
{
DbgPrint("Interface=[%S]\n", pszDeviceInterface);
HANDLE hFile = CreateFileW(pszDeviceInterface, FILE_GENERIC_READ,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
GetDiskPropertyByHandle(hFile);
CloseHandle(hFile);
}
GetPropertyByInterface(prefix, pszDeviceInterface);
pszDeviceInterface += 1 + wcslen(pszDeviceInterface);
}
return CR_SUCCESS;
}
}
}
CONFIGRET EnumDisks()
{
char prefix[256];
memset(prefix, '\t', sizeof(prefix));
prefix[sizeof(prefix) - 1] = 0;
prefix[0] = 0;
return EnumDisks(prefix + sizeof(prefix) - 1, const_cast<PGUID>(&GUID_DEVINTERFACE_DISK));
}
CM_Get_Device_Interface_ListW
return multiple, NULL-terminated Unicode strings, each representing the symbolic link name of an interface instance.
from one side this symbolic link name can be passed to CreateFileW
for open disk device. after this we can set some ioctl to disk - for get
- Index of the Disk
- Capacity
- Serial Number
- Partition Information
example:
void GetDiskPropertyByHandle(HANDLE hDisk)
{
HANDLE hPartition;
IO_STATUS_BLOCK iosb;
STORAGE_DEVICE_NUMBER sdn;
GET_LENGTH_INFORMATION li;
NTSTATUS status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, &sdn, sizeof(sdn));
if (0 <= status && sdn.DeviceType == FILE_DEVICE_DISK && !sdn.PartitionNumber)
{
DbgPrint("\\Device\\Harddisk%d\n", sdn.DeviceNumber);
WCHAR sz[64], *c = sz + swprintf(sz, L"\\Device\\Harddisk%d\\Partition", sdn.DeviceNumber);
WCHAR szSize[32];
if (0 <= (status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_DISK_GET_LENGTH_INFO, 0, 0, &li, sizeof(li))))
{
DbgPrint("Length = %S (%I64x)\n",
StrFormatByteSizeW(li.Length.QuadPart, szSize, RTL_NUMBER_OF(szSize)),
li.Length.QuadPart);
}
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
PSTORAGE_DEVICE_DESCRIPTOR psdd;
PCSTR psz;
};
STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty, PropertyStandardQuery };
ULONG cb = 0, rcb = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 0x40, PartitionCount = 4;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
switch (status = (NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), buf, cb)))
{
case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW:
if (psdd->Version == sizeof(STORAGE_DEVICE_DESCRIPTOR))
{
if (psdd->Size > cb)
{
rcb = psdd->Size;
status = STATUS_BUFFER_OVERFLOW;
}
else
{
if (psdd->SerialNumberOffset)
{
DbgPrint("SerialNumber = %s\n", psz + psdd->SerialNumberOffset);
}
}
}
else
{
status = STATUS_INVALID_PARAMETER;
}
break;
}
} while (status == STATUS_BUFFER_OVERFLOW);
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_DISK_GET_DRIVE_LAYOUT_EX, 0, 0, buf, cb)))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
_itow(PartitionEntry->PartitionNumber, c, 10);
RtlInitUnicodeString(&ObjectName, sz);
DbgPrint("%wZ\nOffset=%S ", &ObjectName,
StrFormatByteSizeW(PartitionEntry->StartingOffset.QuadPart, szSize, RTL_NUMBER_OF(szSize)));
DbgPrint("Length=%S\n",
StrFormatByteSizeW(PartitionEntry->PartitionLength.QuadPart, szSize, RTL_NUMBER_OF(szSize)));
char PartitionName[256], *szPartitionName;
switch (PartitionEntry->PartitionStyle)
{
case PARTITION_STYLE_MBR:
DbgPrint("MBR: type=%x boot=%x", PartitionEntry->Mbr.PartitionType, PartitionEntry->Mbr.BootIndicator);
break;
case PARTITION_STYLE_GPT:
if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_ENTRY_UNUSED_GUID))
{
szPartitionName = "UNUSED";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_SYSTEM_GUID))
{
szPartitionName = "SYSTEM";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_RESERVED_GUID))
{
szPartitionName = "RESERVED";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_BASIC_DATA_GUID))
{
szPartitionName = "DATA";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_RECOVERY_GUID))
{
szPartitionName = "RECOVERY";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_SNAPSHOT_GUID))
{
szPartitionName = "SNAPSHOT";
}
else
{
sprintf(szPartitionName = PartitionName, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
PartitionEntry->Gpt.PartitionType.Data1,
PartitionEntry->Gpt.PartitionType.Data2,
PartitionEntry->Gpt.PartitionType.Data3,
PartitionEntry->Gpt.PartitionType.Data4[0],
PartitionEntry->Gpt.PartitionType.Data4[1],
PartitionEntry->Gpt.PartitionType.Data4[2],
PartitionEntry->Gpt.PartitionType.Data4[3],
PartitionEntry->Gpt.PartitionType.Data4[4],
PartitionEntry->Gpt.PartitionType.Data4[5],
PartitionEntry->Gpt.PartitionType.Data4[6],
PartitionEntry->Gpt.PartitionType.Data4[7]);
}
DbgPrint("[%s] %I64x \"%S\"",
szPartitionName,
PartitionEntry->Gpt.Attributes,
PartitionEntry->Gpt.Name);
break;
}
if (0 <= NtOpenFile(&hPartition, FILE_GENERIC_READ, &oa, &iosb,
FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT))
{
union {
BYTE bb[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 32*sizeof(WCHAR) ];
FILE_FS_ATTRIBUTE_INFORMATION ffai;
};
switch (NtQueryVolumeInformationFile(hPartition, &iosb, &ffai, sizeof(bb), FileFsAttributeInformation))
{
case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW:
DbgPrint(" \"%.*S\"\n", ffai.FileSystemNameLength >> 1 , ffai.FileSystemName);
break;
}
NtClose(hPartition);
}
} while (PartitionEntry++, --PartitionCount);
}
return ;
}
switch (status)
{
case STATUS_BUFFER_OVERFLOW:
PartitionCount = pdli->PartitionCount;
continue;
case STATUS_INFO_LENGTH_MISMATCH:
case STATUS_BUFFER_TOO_SMALL:
PartitionCount <<= 1;
continue;
default:
return ;
}
}
}
}
from another size we can get Device Instance ID from interface string by call CM_Get_Device_Interface_PropertyW
with DEVPKEY_Device_InstanceId
. after this we call CM_Locate_DevNodeW
for get device instance handle.
CONFIGRET GetPropertyByInterface(PCSTR prefix, PCWSTR pszDeviceInterface)
{
ULONG cb = 0, rcb = 256;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
CONFIGRET status;
union {
PVOID pv;
PWSTR DeviceID;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
status = CM_Get_Device_Interface_PropertyW(pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DbgPrint("%sDeviceID = %S\n", prefix, DeviceID);
DEVINST dnDevInst;
if (CR_SUCCESS == (status = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL)))
{
GetPropertyByDeviceID(prefix, dnDevInst);
}
}
else
{
status = CR_WRONG_TYPE;
}
break;
}
} while (status == CR_BUFFER_SMALL);
return status;
}
with device instance handle we can query many device properties via CM_Get_DevNode_PropertyW
like:
DEVPKEY_Device_LocationInfo
, DEVPKEY_NAME
, DEVPKEY_Device_PDOName
, DEVPKEY_Device_FirmwareVersion
, DEVPKEY_Device_Model
, DEVPKEY_Device_DriverVersion
and many others - look full list in devpkey.h
finally we can call CM_Get_Parent
and recursive query all this properties for parent device(s) until we not rich top of stack:
#define OPEN_PDO
void GetPropertyByDeviceID(PCSTR prefix, DEVINST dnDevInst)
{
#ifdef OPEN_PDO
HANDLE hFile;
IO_STATUS_BLOCK iosb;
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
#endif
CONFIGRET status;
ULONG cb = 0, rcb = 0x80;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
union {
PVOID pv;
PWSTR sz;
PBYTE pb;
};
static struct
{
CONST DEVPROPKEY *PropertyKey;
PCWSTR PropertyName;
} PropertyKeys[] = {
{ &DEVPKEY_Device_PDOName, L"PDOName"},
{ &DEVPKEY_Device_Parent, L"Parent"},
{ &DEVPKEY_Device_DriverVersion, L"DriverVersion"},
{ &DEVPKEY_Device_LocationInfo, L"LocationInfo"},
{ &DEVPKEY_Device_FirmwareVersion, L"FirmwareVersion"},
{ &DEVPKEY_Device_Model, L"Model"},
{ &DEVPKEY_NAME, L"NAME"},
{ &DEVPKEY_Device_InstanceId, L"DeviceID"}
};
do
{
int n = RTL_NUMBER_OF(PropertyKeys);
do
{
CONST DEVPROPKEY *PropertyKey = PropertyKeys[--n].PropertyKey;
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
status = CM_Get_DevNode_PropertyW(dnDevInst, PropertyKey, &PropertyType, pb, &rcb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DbgPrint("%s%S=[%S]\n", prefix, PropertyKeys[n].PropertyName, sz);
#ifdef OPEN_PDO
if (!n)
{
// DEVPKEY_Device_PDOName can use in NtOpenFile
RtlInitUnicodeString(&ObjectName, sz);
if (0 <= NtOpenFile(&hFile, FILE_READ_ATTRIBUTES|SYNCHRONIZE, &oa,
&iosb, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT))
{
NtClose(hFile);
}
}
#endif
}
}
} while (status == CR_BUFFER_SMALL);
} while (n);
if (!*--prefix) break;
} while (CM_Get_Parent(&dnDevInst, dnDevInst, 0) == CR_SUCCESS);
}
also string returned by DEVPKEY_Device_PDOName
we can use in NtOpenFile
call for open PDO device.
CM_Get_Device_Interface_List
withGUID_DEVINTERFACE_DISK
and other CM_ api instead SetupDi api.CM_Get_Device_Interface_PropertyW
withDEVPKEY_Device_InstanceId
and thanCM_Locate_DevNodeW
. location -DEVPKEY_Device_LocationInfo
withCM_Get_DevNode_PropertyW
, Capacity, Serial Number - open device and send IOCTLs. really too many questions or you want complete program here – RbMmCM_Get_Device_Interface_List
is perfect working and nothis skip. error in your code – RbMm