c++visual-studiodeviceiocontrol

DeviceIoControl() with IOCTL_DISK_GET_DRIVE_GEOMETRY is failing and returning error code 87. Why?


Relevant code is as follows:

std::wstring path = ApplicationData::Current->LocalFolder->Path->Data();

std::wstring testFileName = path + std::wstring(L"\\TestVariablySized");
this->hMappedFile = CreateFile2(
    testFileName.c_str(),
    GENERIC_READ | GENERIC_WRITE,
    0,
    OPEN_ALWAYS,
    NULL);

uint32_t checkF = GetLastError();

DISK_GEOMETRY geo = { 0 };
DWORD bReturned = 0;

bool controlCheck = DeviceIoControl(
    (HANDLE)hMappedFile,              // handle to device
    IOCTL_DISK_GET_DRIVE_GEOMETRY, // dwIoControlCode
    NULL,                          // lpInBuffer
    0,                             // nInBufferSize
    (LPVOID)&geo,          // output buffer
    (DWORD)sizeof(geo),        // size of output buffer
    (LPDWORD)&bReturned,     // number of bytes returned
    NULL);

uint32_t check = GetLastError();

After this, controlCheck is false and check is ERROR_INVALID_PARAMETER. checkF is ERROR_ALREADY_EXISTS, which shouldn't be a problem here.

As far as I can tell, I've called DeviceIoControl() in a way consistent with the IOCTL_DISK_GET_DRIVE_GEOMETRY documentation. , but clearly I'm missing something. Your help is most appreciated.

Edit:

Per responses received, I altered things to be as follows:

HANDLE hDevice = CreateFile2(
    L"\\.\PhysicalDrive0",
    GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    OPEN_EXISTING,
    NULL);

uint32_t checkF = GetLastError();

DISK_GEOMETRY geo = { 0 };
DWORD bReturned = 0;

bool controlCheck = DeviceIoControl(
    hDevice,              // handle to device
    IOCTL_DISK_GET_DRIVE_GEOMETRY, // dwIoControlCode
    NULL,                          // lpInBuffer
    0,                             // nInBufferSize
    (LPVOID)&geo,          // output buffer
    (DWORD)sizeof(geo),        // size of output buffer
    (LPDWORD)&bReturned,     // number of bytes returned
    NULL);

uint32_t check = GetLastError();

CloseHandle(hDevice);

Which should be closer to being correct, even if it's not quite correct yet. checkF is ERROR_FILE_NOT_FOUND, which I found strange. I tried "\\.\PhysicalDrive1" and "\\.\PhysicalDrive2" as well, but receive the same result. controlCheck is still false, but check is now ERROR_INVALID_HANDLE.


Solution

  • As far as I can tell, I've called DeviceIoControl() in a way consistent with the IOCTL_DISK_GET_DRIVE_GEOMETRY documentation

    Actually, you are not, because you did not pay attention to this tidbit of the documentation:

    hDevice
    A handle to the disk device from which the geometry is to be retrieved. To retrieve a device handle, call the CreateFile function.

    You are not passing a handle to a disk device, you are passing a handle to a filesystem path instead.

    When calling CreateFile2() to get a handle to a disk device, you need to specify a physical device in \\.\PhysicalDriveX format instead, not a filesystem path.

    Also, as the CreateFile2() documentation says:

    The following requirements must be met for such a call to succeed:

    • The caller must have administrative privileges. For more information, see Running with Special Privileges.
    • The dwCreationDisposition parameter must have the OPEN_EXISTING flag.
    • When opening a volume or floppy disk, the dwShareMode parameter must have the FILE_SHARE_WRITE flag.

    You are using OPEN_ALWAYS instead of OPEN_EXISTING.

    Please read the "Physical Disks and Volumes" section of the CreateFile2() documentation more carefully.

    Try something more like this instead:

    std::wstring path = L"\\\\.\\PhysicalDrive0";
    DWORD errCode;
    
    hMappedFile = CreateFile2(
        path.c_str(),
        GENERIC_READ | GENERIC_WRITE,
        0,
        OPEN_EXISTING,
        NULL);
    
    if (this->hMappedFile == INVALID_HANDLE_VALUE)
    {
        errCode = GetLastError();
        // handle error as needed...
    }
    else
    {
        DISK_GEOMETRY geo = { 0 };
        DWORD dwReturned = 0;
    
        bool controlCheck = DeviceIoControl(
            hMappedFile,                   // handle to device
            IOCTL_DISK_GET_DRIVE_GEOMETRY, // dwIoControlCode
            NULL,                          // lpInBuffer
            0,                             // nInBufferSize
            &geo,                          // output buffer
            sizeof(geo),                   // size of output buffer
            &dwReturned,                   // number of bytes returned
            NULL);
    
        if (!controlCheck)
        {
            errCode = GetLastError();
            // handle error as needed...
        }
        else
        {
            // use drive as needed...
        }
    
        CloseHandle(hMappedFile);
    }