【问题标题】:How to enumerate the volumes on a phyiscal drive using Windows API?如何使用 Windows API 枚举物理驱动器上的卷?
【发布时间】:2015-11-09 18:18:49
【问题描述】:

我正在尝试创建系统中所有(固定)磁盘的分区及其卷的列表(例如:PhyiscalDrive0,Partition 1,C:\; PhyiscalDrive0,Partition 2,D:\; .. .) .我已经通过 SetupApi 和 IOCTL_STORAGE_GET_DEVICE_NUMBER 得到了已安装磁盘的列表,以及分区数。

我遇到的问题是如何找出挂载到特定分区的驱动器号(例如物理驱动器的分区 1 是 C:\)?

感谢之前的任何帮助,

威利·K.

【问题讨论】:

  • 安装的卷不一定有驱动器号。分区也可以跨越多个驱动器。

标签: winapi hardware enumeration


【解决方案1】:

您可能想要使用的 API 是 Storage Management API。这提供了一种查询任何你想要的东西的方法。特别是,驱动器号是MSFT_Volume 类的一部分。该 API 对 C++ 不是最友好的,这就是为什么我不提供示例查询的原因,但是有一个 sample here 显示了如何编写查询。

【讨论】:

  • 感谢您的回复,埃里克·布朗。我给了你一个答案 - 但是我不得不承认我目前选择了另一种方式(枚举卷并使用 IOCTL_STORAGE_GET_DEVICE_NUMBER 告诉我驱动器号和分区号)。当另一条路变得绝对必要时,我会回到这一点。
【解决方案2】:

一旦您通过 setup api 获得驱动器,您需要获取有关分区的信息(通过 IOCTL_DISK_GET_DRIVE_LAYOUT_EX),尤其是它们的起始偏移量和长度。 这是我在库 libwindevblk (libwindevblk) 中使用的代码:

BOOL FindVolume(int diskno, PSMI_DEVBLK_ENTRY pDevBlkEntry) 
{
HANDLE vol;
BOOL success;
TCHAR szNextVolName[MAX_PATH+1];
TCHAR szNextVolNameNoBSlash[MAX_PATH+1];

vol = FindFirstVolume(szNextVolName, MAX_PATH);
success = (vol != INVALID_HANDLE_VALUE);
while (success)
{
    //We are now enumerating volumes. In order for this function to work, we need to get partitions that compose this volume
    HANDLE volH;
    PVOLUME_DISK_EXTENTS vde;
    DWORD bret;

    //For this CreateFile, volume must be without trailing backslash
    StringCchCopy(szNextVolNameNoBSlash, MAX_PATH, szNextVolName);
    szNextVolNameNoBSlash[_tcslen(szNextVolNameNoBSlash) - 1] = _T('\0'); 

    volH = CreateFile(szNextVolNameNoBSlash,
        FILE_READ_ATTRIBUTES | SYNCHRONIZE | FILE_TRAVERSE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, 0, 0);

    if (volH != INVALID_HANDLE_VALUE)
    {
        bret = sizeof(VOLUME_DISK_EXTENTS) + 256 * sizeof(DISK_EXTENT);
        vde = (PVOLUME_DISK_EXTENTS)malloc(bret);
        if (DeviceIoControl(volH, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, (void *)vde, bret, &bret, NULL))
        {
            for (unsigned i = 0; i < vde->NumberOfDiskExtents; i++)
            {
                if (vde->Extents[i].DiskNumber == diskno &&
                    vde->Extents[i].StartingOffset.QuadPart == pDevBlkEntry->StartingOffset.QuadPart &&
                    vde->Extents[i].ExtentLength.QuadPart == pDevBlkEntry->PartitionLength.QuadPart)
                {
                    CHAR szVolumeName[MAX_PATH + 1] = { 0 };
                    CHAR szFileSystemName[MAX_PATH + 1] = { 0 };
                    DWORD dwSerialNumber = 0;
                    DWORD dwMaxFileNameLength = 0;
                    DWORD dwFileSystemFlags = 0;

                    if (GetVolumeInformation(szNextVolName,
                        szVolumeName, _countof(szVolumeName),
                        &dwSerialNumber,
                        &dwMaxFileNameLength,
                        &dwFileSystemFlags,
                        szFileSystemName,
                        _countof(szFileSystemName)))
                    {
                        _tcsncpy(pDevBlkEntry->szRootPathName, szNextVolName, MAX_PATH);
                        _tcsncpy(pDevBlkEntry->szVolumeName, szVolumeName, MAX_PATH);
                        _tcsncpy(pDevBlkEntry->szFileSystemName, szFileSystemName, MAX_PATH);
                        pDevBlkEntry->dwSerialNumber = dwSerialNumber;
                        pDevBlkEntry->dwFileSystemFlags = dwFileSystemFlags;
                    }
                    else
                    {
                        DWORD dwErr = GetLastError();
                        printf("%lu", dwErr);
                    }

                    DWORD length = 0;
                    TCHAR pathnames[MAX_PATH + 1] = { 0 };
                    if (GetVolumePathNamesForVolumeName(szNextVolName, (LPTSTR)pathnames, MAX_PATH, &length))
                    {
                        _tcsncpy(pDevBlkEntry->szVolumePathName, pathnames, MAX_PATH);
                    }

                    free(vde);
                    CloseHandle(volH);
                    FindVolumeClose(vol);
                    return TRUE;
                } 
            }//for
        }
        free(vde);
        CloseHandle(volH);
    }

    success = FindNextVolume(vol, szNextVolName, MAX_PATH) != 0;
}
FindVolumeClose(vol);
return FALSE;

}

【讨论】:

  • 对于某些卷 CreateFile 在使用 FILE_READ_ATTRIBUTES | SYNCHRONIZE | FILE_TRAVERSE 时失败并显示“访问被拒绝” - 使用 0 为我修复了它。
猜你喜欢
  • 2011-04-18
  • 2016-10-02
  • 2014-03-27
  • 2023-03-26
  • 2010-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
相关资源
最近更新 更多