如何从设备管理器设备(例如从其 "Physical Device Object name")获取其驱动器号?
How to get from device-manager device (e.g. from its "Physical Device Object name") to its drive-letter?
从设备管理器中,我有一个 USB 设备节点。我提取了它的"Physical Device Object name"(例如\Device[=11=]00010f
)。
与 NtOpenDirectoryObject
、NtQueryDirectoryObject
、NtOpenSymbolicLinkObject
、NtQuerySymbolicLinkObject
和 QueryDosDevice
战斗数小时后,我找不到解决方法"Physical Device Object name" 到实际的驱动器号(C:
、D:
、...)。
我正在寻找任何存储解决方案 (USB/SATA/...)。我该怎么做?
(有很多类似的问题,其中 none 回答了例如如何从物理设备对象名称到 \Device\HarddiskVolumeXYZ
或 Volume{SOME_GUID}
)
你看到的\Device[=11=]00010f
这是由一些总线驱动程序创建的PDO(物理设备对象)(它有标志DO_BUS_ENUMERATED_DEVICE
)
它可以附加一些 FDO(功能设备对象)。如果这是来自存储堆栈(基于 CompatibleIDs 总线设备为此 PDO 返回的字符串)典型的 FDO 名字有形式 \Device\Harddisk%d\DR%d
和众所周知的符号 link \Device\Harddisk%d\Partition0
磁盘驱动程序 FDO 枚举卷上的分区并为每个分区创建 PDO 设备对象(具有众所周知的符号 link \Device\Harddisk%d\Partition%d
其中分区号总是 > 0,Partition0 是指整个磁盘 FDO)
通常的分区与卷相同,但并非总是如此 (Partitions and Volumes) also note IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
- it return array of DISK_EXTENT
structures - look here for DiskNumber -The number of the disk that contains this extent.
so volume can placed on several disks. but in 99%+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
return to you only one DISK_EXTENT
那么,如果您在存储堆栈中有 PDO 的路径,您可以做什么?
- 打开设备 - 如果使用
ZwOpenFile
(当然这在
用户模式)我们可以按原样使用 \Device[=11=]00010f
。如果我们想使用 win32
api 我们需要为所有名称使用前缀 \?\GLOBALROOT
。我们实际上是通过这条总线 PDO 打开的,但是因为磁盘 FDO 附加到 PDO 我们所有的请求都将是通过 FDO 发送并在此处处理。所需的访问权限? SYNCHRONIZE
就足够了(如果 CreateFile
如果我们不设置 FILE_FLAG_OVERLAPPED
api 隐式将此标志添加到 DESIRED_ACCESS
)
- 发送
IOCTL_STORAGE_GET_DEVICE_NUMBER
到设备。检查那个
DeviceType == FILE_DEVICE_DISK && sdn.PartitionNumber == 0
- 发送
IOCTL_DISK_GET_DRIVE_LAYOUT_EX
获取可变大小
PARTITION_INFORMATION_EX
结构数组
- 基于
DeviceNumber
(我们在第 2 步得到)和
PartitionNumber
(我们在第 3 步得到)格式化符号 link 到
分区 PDO - \?\GLOBALROOT\Device\Harddisk%d\Partition%d
- 打开分区 PDO 并具有
SYNCHRONIZE
访问权限(足够了,因为所有
我们使用的IOCTL有FILE_ANY_ACCESS
类型
- 发送
IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
到分区
- 现在我们需要 MountManager 设备的句柄 (
\.\MountPointManager
)
发送给他 IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
这个 IOCTL 在输入中定义 mountmgr.h
它需要 MOUNTDEV_NAME
我们在第 6 步得到。在输出中我们收到 MOUNTMGR_VOLUME_PATHS
结构(也在 mountmgr.h
中定义)或者我们可以使用
IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS
- 如果一切正常,我们得到列表
C:
、D:
等驱动器号。
- 我们可以使用枚举系统中的磁盘驱动器
CM_Get_Device_ID_ListW
与
{4d36e967-e325-11ce-bfc1-08002be10318}
过滤,打开每一个设备
通过 CM_Locate_DevNodeW
实例并最终查询
DEVPKEY_Device_PDOName
通过电话
CM_Get_DevNode_Property
好的,这里是正确的代码示例,可以完成所有这些操作:
#include <mountmgr.h>
// guz == 0 always, volatile for prevent CL "optimization" - it can drop alloca(0) call
static volatile UCHAR guz;
ULONG QueryPartitionW32(HANDLE hPartition, HANDLE hMountManager)
{
MOUNTDEV_STABLE_GUID guid;
ULONG dwBytesRet;
if (DeviceIoControl(hPartition, IOCTL_MOUNTDEV_QUERY_STABLE_GUID, 0, 0, &guid, sizeof(guid), &dwBytesRet, NULL))
{
DbgPrint("StableGuid = \\?\Volume{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
guid.StableGuid.Data1, guid.StableGuid.Data2, guid.StableGuid.Data3,
guid.StableGuid.Data4[0],
guid.StableGuid.Data4[1],
guid.StableGuid.Data4[2],
guid.StableGuid.Data4[3],
guid.StableGuid.Data4[4],
guid.StableGuid.Data4[5],
guid.StableGuid.Data4[6],
guid.StableGuid.Data4[7]
);
}
// assume NumberOfDiskExtents == 1
VOLUME_DISK_EXTENTS vde;
if (DeviceIoControl(hPartition, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 0, 0, &vde, sizeof(vde), &dwBytesRet, 0))
{
if (vde.NumberOfDiskExtents)
{
DbgPrint("ofs=%I64u, len=%I64u\n", vde.Extents->StartingOffset.QuadPart, vde.Extents->ExtentLength.QuadPart);
}
}
PVOID stack = alloca(guz);
union {
PVOID buf;
PMOUNTDEV_NAME pmdn;
};
ULONG err;
ULONG cb = 0, rcb = sizeof(MOUNTDEV_NAME) + 0x10, InputBufferLength;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hPartition, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 0, 0, buf, cb, &dwBytesRet, NULL))
{
DbgPrint("%.*S\n", pmdn->NameLength >> 1, pmdn->Name);
union {
PVOID pv;
PMOUNTMGR_VOLUME_PATHS pmvp;
};
cb = 0, rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + 0x10, InputBufferLength = sizeof(MOUNTDEV_NAME) + pmdn->NameLength;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(pv = alloca(rcb - cb), pmdn);
}
if (DeviceIoControl(hMountManager, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
pmdn, InputBufferLength, pv, cb, &dwBytesRet, NULL))
{
PWSTR sz = pmvp->MultiSz;
while(*sz)
{
DbgPrint("%S\n", sz);
sz += 1 + wcslen(sz);
}
return NOERROR;
}
rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + pmvp->MultiSzLength;
} while ((err = GetLastError()) == ERROR_MORE_DATA);
break;
}
rcb = sizeof(MOUNTDEV_NAME) + pmdn->NameLength;
} while ((err = GetLastError()) == ERROR_MORE_DATA);
return err;
}
ULONG EnumDiskPartitionsW32(HANDLE hDisk, HANDLE hMountManager)
{
STORAGE_DEVICE_NUMBER sdn;
ULONG dwBytesRet;
if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL))
{
return GetLastError();
}
if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0)
{
return ERROR_GEN_FAILURE;
}
WCHAR sz[128], *c = sz + swprintf(sz, L"\\?\GLOBALROOT\Device\Harddisk%d\Partition", sdn.DeviceNumber);
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
};
ULONG cb = 0, rcb, PartitionCount = 4;
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
_itow(PartitionEntry->PartitionNumber, c, 10);
DbgPrint("%S\n", sz);
HANDLE hPartition = CreateFile(sz, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hPartition != INVALID_HANDLE_VALUE)
{
QueryPartitionW32(hPartition, hMountManager);
CloseHandle(hPartition);
}
} while (PartitionEntry++, --PartitionCount);
}
return NOERROR;
}
switch (ULONG err = GetLastError())
{
case ERROR_MORE_DATA:
PartitionCount = pdli->PartitionCount;
continue;
case ERROR_BAD_LENGTH:
case ERROR_INSUFFICIENT_BUFFER:
PartitionCount <<= 1;
continue;
default:
return err;
}
}
}
void DiskEnumW32(HANDLE hMountManager)
{
static const WCHAR DEVCLASS_DISK[] = L"{4d36e967-e325-11ce-bfc1-08002be10318}";
enum { flags = CM_GETIDLIST_FILTER_CLASS|CM_GETIDLIST_FILTER_PRESENT };
ULONG len;
if (!CM_Get_Device_ID_List_SizeW(&len, DEVCLASS_DISK, flags))
{
PWSTR buf = (PWSTR)alloca(len * sizeof(WCHAR));
if (!CM_Get_Device_ID_ListW(DEVCLASS_DISK, buf, len, flags))
{
PVOID stack = buf;
static const WCHAR prefix[] = L"\\?\GLOBALROOT";
ULONG cb = 0, rcb = sizeof(prefix) + 0x20;
while (*buf)
{
DbgPrint("%S\n", buf);
DEVINST dnDevInst;
if (!CM_Locate_DevNodeW(&dnDevInst, buf, CM_LOCATE_DEVNODE_NORMAL))
{
DEVPROPTYPE PropertyType;
int err;
union {
PVOID pv;
PWSTR sz;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
rcb -= sizeof(prefix) - sizeof(WCHAR);
if (!(err = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_Device_PDOName, &PropertyType,
pb + sizeof(prefix) - sizeof(WCHAR), &rcb, 0)))
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
memcpy(pv, prefix, sizeof(prefix) - sizeof(WCHAR));
DbgPrint("%S\n", sz);
HANDLE hDisk = CreateFile(sz, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hDisk != INVALID_HANDLE_VALUE)
{
EnumDiskPartitionsW32(hDisk, hMountManager);
CloseHandle(hDisk);
}
}
else
{
err = ERROR_GEN_FAILURE;
}
break;
}
rcb += sizeof(prefix) - sizeof(WCHAR);
} while (err == CR_BUFFER_SMALL);
}
buf += 1 + wcslen(buf);
}
}
}
}
void DiskEnumW32()
{
HANDLE hMountManager = CreateFile(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hMountManager != INVALID_HANDLE_VALUE)
{
DiskEnumW32(hMountManager);
CloseHandle(hMountManager);
}
}
另一种可能的解决方案,仅基于 PowerShell 和 WMI:
$PDO = "\Device[=10=]000052"
$DiskDriverData = Get-WmiObject Win32_PNPSignedDriver | Where {$_.PDO -eq $PDO}
$DeviceID = """" + $DiskDriverData.DeviceID.Replace("\","\") + """"
$ComputerInfo = Get-WmiObject Win32_Computersystem
$name = $ComputerInfo.Name
$FullString = "\$name\root\cimv2:Win32_PnPEntity.DeviceID=$DeviceID"
$PNPDevice = Get-WmiObject Win32_PNPDevice | Where {$_.SystemElement -eq $FullString}
$DiskDriveToPartition = Get-WmiObject -Class Win32_DiskDriveToDiskPartition | where {$_.Antecedent -eq $PNPDevice.SameElement}
foreach ($i in $DiskDriveToPartition) {
$Partition = Get-WmiObject -Class Win32_LogicalDiskToPartition | Where {$_.Antecedent -eq $i.Dependent}
$PartitionLetter = $Partition.Dependent.split('"')[1]
Write-Host -ForegroundColor Green "Detected Partition for the given PDO: $PartitionLetter"
}
从设备管理器中,我有一个 USB 设备节点。我提取了它的"Physical Device Object name"(例如\Device[=11=]00010f
)。
与 NtOpenDirectoryObject
、NtQueryDirectoryObject
、NtOpenSymbolicLinkObject
、NtQuerySymbolicLinkObject
和 QueryDosDevice
战斗数小时后,我找不到解决方法"Physical Device Object name" 到实际的驱动器号(C:
、D:
、...)。
我正在寻找任何存储解决方案 (USB/SATA/...)。我该怎么做?
(有很多类似的问题,其中 none 回答了例如如何从物理设备对象名称到 \Device\HarddiskVolumeXYZ
或 Volume{SOME_GUID}
)
你看到的\Device[=11=]00010f
这是由一些总线驱动程序创建的PDO(物理设备对象)(它有标志DO_BUS_ENUMERATED_DEVICE
)
它可以附加一些 FDO(功能设备对象)。如果这是来自存储堆栈(基于 CompatibleIDs 总线设备为此 PDO 返回的字符串)典型的 FDO 名字有形式 \Device\Harddisk%d\DR%d
和众所周知的符号 link \Device\Harddisk%d\Partition0
磁盘驱动程序 FDO 枚举卷上的分区并为每个分区创建 PDO 设备对象(具有众所周知的符号 link \Device\Harddisk%d\Partition%d
其中分区号总是 > 0,Partition0 是指整个磁盘 FDO)
通常的分区与卷相同,但并非总是如此 (Partitions and Volumes) also note IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
- it return array of DISK_EXTENT
structures - look here for DiskNumber -The number of the disk that contains this extent.
so volume can placed on several disks. but in 99%+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
return to you only one DISK_EXTENT
那么,如果您在存储堆栈中有 PDO 的路径,您可以做什么?
- 打开设备 - 如果使用
ZwOpenFile
(当然这在 用户模式)我们可以按原样使用\Device[=11=]00010f
。如果我们想使用 win32 api 我们需要为所有名称使用前缀\?\GLOBALROOT
。我们实际上是通过这条总线 PDO 打开的,但是因为磁盘 FDO 附加到 PDO 我们所有的请求都将是通过 FDO 发送并在此处处理。所需的访问权限?SYNCHRONIZE
就足够了(如果CreateFile
如果我们不设置FILE_FLAG_OVERLAPPED
api 隐式将此标志添加到DESIRED_ACCESS
) - 发送
IOCTL_STORAGE_GET_DEVICE_NUMBER
到设备。检查那个DeviceType == FILE_DEVICE_DISK && sdn.PartitionNumber == 0
- 发送
IOCTL_DISK_GET_DRIVE_LAYOUT_EX
获取可变大小PARTITION_INFORMATION_EX
结构数组 - 基于
DeviceNumber
(我们在第 2 步得到)和PartitionNumber
(我们在第 3 步得到)格式化符号 link 到 分区 PDO -\?\GLOBALROOT\Device\Harddisk%d\Partition%d
- 打开分区 PDO 并具有
SYNCHRONIZE
访问权限(足够了,因为所有 我们使用的IOCTL有FILE_ANY_ACCESS
类型 - 发送
IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
到分区 - 现在我们需要 MountManager 设备的句柄 (
\.\MountPointManager
) 发送给他IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
这个 IOCTL 在输入中定义mountmgr.h
它需要MOUNTDEV_NAME
我们在第 6 步得到。在输出中我们收到MOUNTMGR_VOLUME_PATHS
结构(也在mountmgr.h
中定义)或者我们可以使用IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS
- 如果一切正常,我们得到列表C:
、D:
等驱动器号。 - 我们可以使用枚举系统中的磁盘驱动器
CM_Get_Device_ID_ListW
与{4d36e967-e325-11ce-bfc1-08002be10318}
过滤,打开每一个设备 通过CM_Locate_DevNodeW
实例并最终查询DEVPKEY_Device_PDOName
通过电话CM_Get_DevNode_Property
好的,这里是正确的代码示例,可以完成所有这些操作:
#include <mountmgr.h>
// guz == 0 always, volatile for prevent CL "optimization" - it can drop alloca(0) call
static volatile UCHAR guz;
ULONG QueryPartitionW32(HANDLE hPartition, HANDLE hMountManager)
{
MOUNTDEV_STABLE_GUID guid;
ULONG dwBytesRet;
if (DeviceIoControl(hPartition, IOCTL_MOUNTDEV_QUERY_STABLE_GUID, 0, 0, &guid, sizeof(guid), &dwBytesRet, NULL))
{
DbgPrint("StableGuid = \\?\Volume{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
guid.StableGuid.Data1, guid.StableGuid.Data2, guid.StableGuid.Data3,
guid.StableGuid.Data4[0],
guid.StableGuid.Data4[1],
guid.StableGuid.Data4[2],
guid.StableGuid.Data4[3],
guid.StableGuid.Data4[4],
guid.StableGuid.Data4[5],
guid.StableGuid.Data4[6],
guid.StableGuid.Data4[7]
);
}
// assume NumberOfDiskExtents == 1
VOLUME_DISK_EXTENTS vde;
if (DeviceIoControl(hPartition, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 0, 0, &vde, sizeof(vde), &dwBytesRet, 0))
{
if (vde.NumberOfDiskExtents)
{
DbgPrint("ofs=%I64u, len=%I64u\n", vde.Extents->StartingOffset.QuadPart, vde.Extents->ExtentLength.QuadPart);
}
}
PVOID stack = alloca(guz);
union {
PVOID buf;
PMOUNTDEV_NAME pmdn;
};
ULONG err;
ULONG cb = 0, rcb = sizeof(MOUNTDEV_NAME) + 0x10, InputBufferLength;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hPartition, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 0, 0, buf, cb, &dwBytesRet, NULL))
{
DbgPrint("%.*S\n", pmdn->NameLength >> 1, pmdn->Name);
union {
PVOID pv;
PMOUNTMGR_VOLUME_PATHS pmvp;
};
cb = 0, rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + 0x10, InputBufferLength = sizeof(MOUNTDEV_NAME) + pmdn->NameLength;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(pv = alloca(rcb - cb), pmdn);
}
if (DeviceIoControl(hMountManager, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
pmdn, InputBufferLength, pv, cb, &dwBytesRet, NULL))
{
PWSTR sz = pmvp->MultiSz;
while(*sz)
{
DbgPrint("%S\n", sz);
sz += 1 + wcslen(sz);
}
return NOERROR;
}
rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + pmvp->MultiSzLength;
} while ((err = GetLastError()) == ERROR_MORE_DATA);
break;
}
rcb = sizeof(MOUNTDEV_NAME) + pmdn->NameLength;
} while ((err = GetLastError()) == ERROR_MORE_DATA);
return err;
}
ULONG EnumDiskPartitionsW32(HANDLE hDisk, HANDLE hMountManager)
{
STORAGE_DEVICE_NUMBER sdn;
ULONG dwBytesRet;
if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL))
{
return GetLastError();
}
if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0)
{
return ERROR_GEN_FAILURE;
}
WCHAR sz[128], *c = sz + swprintf(sz, L"\\?\GLOBALROOT\Device\Harddisk%d\Partition", sdn.DeviceNumber);
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
};
ULONG cb = 0, rcb, PartitionCount = 4;
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
_itow(PartitionEntry->PartitionNumber, c, 10);
DbgPrint("%S\n", sz);
HANDLE hPartition = CreateFile(sz, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hPartition != INVALID_HANDLE_VALUE)
{
QueryPartitionW32(hPartition, hMountManager);
CloseHandle(hPartition);
}
} while (PartitionEntry++, --PartitionCount);
}
return NOERROR;
}
switch (ULONG err = GetLastError())
{
case ERROR_MORE_DATA:
PartitionCount = pdli->PartitionCount;
continue;
case ERROR_BAD_LENGTH:
case ERROR_INSUFFICIENT_BUFFER:
PartitionCount <<= 1;
continue;
default:
return err;
}
}
}
void DiskEnumW32(HANDLE hMountManager)
{
static const WCHAR DEVCLASS_DISK[] = L"{4d36e967-e325-11ce-bfc1-08002be10318}";
enum { flags = CM_GETIDLIST_FILTER_CLASS|CM_GETIDLIST_FILTER_PRESENT };
ULONG len;
if (!CM_Get_Device_ID_List_SizeW(&len, DEVCLASS_DISK, flags))
{
PWSTR buf = (PWSTR)alloca(len * sizeof(WCHAR));
if (!CM_Get_Device_ID_ListW(DEVCLASS_DISK, buf, len, flags))
{
PVOID stack = buf;
static const WCHAR prefix[] = L"\\?\GLOBALROOT";
ULONG cb = 0, rcb = sizeof(prefix) + 0x20;
while (*buf)
{
DbgPrint("%S\n", buf);
DEVINST dnDevInst;
if (!CM_Locate_DevNodeW(&dnDevInst, buf, CM_LOCATE_DEVNODE_NORMAL))
{
DEVPROPTYPE PropertyType;
int err;
union {
PVOID pv;
PWSTR sz;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
rcb -= sizeof(prefix) - sizeof(WCHAR);
if (!(err = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_Device_PDOName, &PropertyType,
pb + sizeof(prefix) - sizeof(WCHAR), &rcb, 0)))
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
memcpy(pv, prefix, sizeof(prefix) - sizeof(WCHAR));
DbgPrint("%S\n", sz);
HANDLE hDisk = CreateFile(sz, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hDisk != INVALID_HANDLE_VALUE)
{
EnumDiskPartitionsW32(hDisk, hMountManager);
CloseHandle(hDisk);
}
}
else
{
err = ERROR_GEN_FAILURE;
}
break;
}
rcb += sizeof(prefix) - sizeof(WCHAR);
} while (err == CR_BUFFER_SMALL);
}
buf += 1 + wcslen(buf);
}
}
}
}
void DiskEnumW32()
{
HANDLE hMountManager = CreateFile(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hMountManager != INVALID_HANDLE_VALUE)
{
DiskEnumW32(hMountManager);
CloseHandle(hMountManager);
}
}
另一种可能的解决方案,仅基于 PowerShell 和 WMI:
$PDO = "\Device[=10=]000052"
$DiskDriverData = Get-WmiObject Win32_PNPSignedDriver | Where {$_.PDO -eq $PDO}
$DeviceID = """" + $DiskDriverData.DeviceID.Replace("\","\") + """"
$ComputerInfo = Get-WmiObject Win32_Computersystem
$name = $ComputerInfo.Name
$FullString = "\$name\root\cimv2:Win32_PnPEntity.DeviceID=$DeviceID"
$PNPDevice = Get-WmiObject Win32_PNPDevice | Where {$_.SystemElement -eq $FullString}
$DiskDriveToPartition = Get-WmiObject -Class Win32_DiskDriveToDiskPartition | where {$_.Antecedent -eq $PNPDevice.SameElement}
foreach ($i in $DiskDriveToPartition) {
$Partition = Get-WmiObject -Class Win32_LogicalDiskToPartition | Where {$_.Antecedent -eq $i.Dependent}
$PartitionLetter = $Partition.Dependent.split('"')[1]
Write-Host -ForegroundColor Green "Detected Partition for the given PDO: $PartitionLetter"
}