如何使用 Windows API 枚举物理驱动器上的卷?

问题描述 投票:0回答:2

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

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

感谢之前的任何帮助,

威利·K.

winapi hardware enumeration
2个回答
2
投票

您可能想要使用的 API 是 存储管理 API。这提供了一种查询您想要的任何内容的方法。特别是,驱动器号是 MSFT_Volume 类的一部分。该 API 对于 C++ 来说并不是最友好的,这就是为什么我不提供示例查询,但这里有一个 sample 展示了如何编写查询。


1
投票

通过设置 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;

}

© www.soinside.com 2019 - 2024. All rights reserved.