我正在使用:
DWORD d = GetLogicalDrives();
for (int i = 0; i < 26; i++)
{
if ((1 << i) & d) // drive letter 'A' + i present on computer
{
wstring s = std::wstring(L"\\\\.\\") + wchar_t('A' + i) + L":";
PARTITION_INFORMATION diskInfo;
DWORD dwResult;
HANDLE dev = CreateFile(LPWSTR(s.c_str()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &diskInfo, sizeof(diskInfo), &dwResult, NULL);
CloseHandle(dev);
if (diskInfo.PartitionType == PARTITION_IFS)
{
...
}
}
}
枚举计算机的所有NTFS分区。
它适用于我的Windows 7,在Windows 8.1上我试过它,在Windows 10计算机上。
但它在另一台Windows 10计算机上失败:在这一台上,音量C:
的diskInfo.PartitionType
值等于0x00
,而不是0x07
(PARTITION_IFS
)。
这个值是(参见doc here):
PARTITION_ENTRY_UNUSED:0x00:未使用的条目分区。
这很奇怪,因为我可以确认,分区确实是NTFS。
问题:
IOCTL_DISK_GET_PARTITION_INFO
获得分区类型并不是100%可靠吗?注意:我也看了使用IOCTL_DISK_GET_PARTITION_INFO_EX
而不是IOCTL_DISK_GET_PARTITION_INFO
,但结构PARTITION_INFORMATION_EX
似乎没有给出关于PartitionType
的信息,而结构PARTITION_INFORMATION
确实提供了访问PartitionType
。
正如@RemyLebeau所说,您没有检查每个呼叫的返回值。
PARTITION_ENTRY_UNUSED
通常意味着DeviceIoControl()
呼叫失败。这取决于您的用户的权限。您应检查用户的访问权限,以查看它是否具有卷FILE_READ_DATA
上的GENERIC_READ
权限(包含在C:
中)。在我的测试环境中,如果你无法使用C:
访问开放量GENERIC_READ
,CreateFile()
将返回INVALID_HANDLE_VALUE
,然后DeviceIoControl()
也会失败。
编辑:
我建议使用GetVolumeInformation()
,例如:
wchar_t fs[MAX_PATH + 1] = { 0 };
GetVolumeInformationW(L"C:\\", NULL, 0, NULL, NULL, NULL, fs, MAX_PATH + 1);
您将在fs
缓冲区中看到Type信息。
由于@ RemyLebeau的评论,我做了进一步的调查:
HANDLE dev = CreateFile(..., GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if (dev == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError(); // then MessageBox
}
else
{
BOOL ret = DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &diskInfo, sizeof(diskInfo), &dwResult, NULL);
if (ret == FALSE)
{
DWORD err = GetLastError(); // then MessageBox
}
CloseHandle(dev);
}
在它失败的计算机上(使用Windows 10的计算机)。我发现CreateFile
成功,但随后DeviceIoControl
失败,GetLastError
是1
,即ERROR_INVALID_FUNCTION
(见System Error Codes (0-499))。
结论(我引用雷米的评论):
这意味着您传递给DeviceIoControl()的设备不支持IOCTL_DISK_GET_PARTITION_INFO。
然后我尝试使用IOCTL_DISK_GET_PARTITION_INFO_EX
:
PARTITION_INFORMATION_EX diskInfo;
BOOL ret = DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &diskInfo, sizeof(diskInfo), &lpBytesReturned, NULL);
然后它奏效了。我可以看到diskInfo.PartitionStyle
是PARTITION_STYLE_GPT
(= 1),这就是IOCTL_DISK_GET_PARTITION_INFO
失败的原因。我再次引用雷米的评论:
GPT分区驱动器不支持IOCTL_DISK_GET_PARTITION_INFO。
所以这是结论:
IOCTL_DISK_GET_PARTITION_INFO_EX
而不是IOCTL_DISK_GET_PARTITION_INFO
如果diskInfo.PartitionStyle
为0(PARTITION_STYLE_MBR),则可以测试diskInfo.Mbr.PartitionType。 If it's 0x07, it's NTFS。
如果diskInfo.PartitionStyle
为1(PARTITION_STYLE_GPT),则可以测试diskInfo.Gpt.PartitionType,请参见此处:https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_partition_information_gpt。即使NTFS Wikipedia page在GPT案例中提到了NTFS的GUID EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
,这个GUID实际上与文件系统无关(请参阅下面的评论)。GetVolumeInformation()
而只是比较,如果结果是"NTFS"
字符串,如在other answerDeviceIoControl(hVol, FSCTL_ENUM_USN_DATA, ...)
进行索引之前测试卷是否为NTFS,因为我认为这样的MFT查询将限于NTFS卷。事实上,一个更简单的解决方案是,如果它是NTFS,则不测试,只需做FSCTL_ENUM_USN_DATA
。根据文档,可能发生的最糟糕的情况是FSCTL_ENUM_USN_DATA
因ERROR_INVALID_FUNCTION
错误而失败:
“ERROR_INVALID_FUNCTION指定卷上的文件系统不支持此控制代码。”