MNagy MNagy - 25 days ago 12
C++ Question

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
.

Answer

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);
}
Comments