您查看的内容\Device\0000010f
这是PDO(物理设备通过一些总线驱动器创建的对象)(它具有标志DO_BUS_ENUMERATED_DEVICE
)
到它可以被附加了一些FDO (功能设备对象)。如果这是从存储堆栈(基于CompatibleIDs串通过总线装置为这个PDO返回)典型FDO名称具有形式\Device\Harddisk%d\DR%d
和公知的符号链接到它\Device\Harddisk%d\Partition0
磁盘驱动器FDO枚举分区体积和为每一个分区上创建PDO设备对象(与公知的符号链接\Device\Harddisk%d\Partition%d
其中分区号总是> 0,Partition0是指整个磁盘FDO)
平常分区是相同的体积,但并不总是(Partitions and Volumes)也注意到IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
- 它返回DISK_EXTENT
结构的阵列 - 看看这里的DiskNumber -The number of the disk that contains this extent.
因此体积可以放在多个磁盘。但在99%+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
回报你只一个DISK_EXTENT
所以如果你有路径存储堆栈,你可以做PDO什么?
- 打开设备 - 如果使用
ZwOpenFile
(当然这在 用户模式下工作),我们可以使用\Device\0000010f
原样。如果我们要使用win32 api,我们需要为所有名称使用前缀\\?\GLOBALROOT
。我们真的可以乘坐该巴士PDO打开,但因为磁盘FDO连接到PDO我们所有的请求都将通过被发送FDO和这里处理。期望的访问?SYNCHRONIZE
就足够了(如果我们没有设置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获得),以 的分区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
- 如果一切OK,我们像C:
得到了 盘符列表,D:
等。
- 在系统枚举磁盘驱动器,我们可以通过使用
CM_Locate_DevNodeW
CM_Get_Device_ID_ListW
与 {4d36e967-e325-11ce-bfc1-08002be10318}
过滤器,打开每个设备 实例,并最终通过电话查询 DEVPKEY_Device_PDOName
CM_Get_DevNode_Property
OK,到这里代码示例正确的做到了这一切:
#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);
}
}
没有1:1映射为此,您可以有多个驱动器号安装在一个物理设备上。最好逐个查看驱动器号,找出他们的物理设备。 –
@JonathanPotter,当然,但有1:N映射,在这种情况下,我需要安装在该设备上的所有分区(反之亦然 - 设备来自分区,并不重要)。好的 - “最好逐个查阅驱动器号并找出他们的物理设备” - 如何? – Tar
@Tar:也没有1:N映射。卷不需要分配驱动器号。驱动器盘符从MS DOS新的日子里就被遗留下来了。 – IInspectable