不正确的函数调用"IOCTL_DISK_GET_DRIVE_LAYOUT_EX"

Incorrect Function Call "IOCTL_DISK_GET_DRIVE_LAYOUT_EX"

本文关键字:DRIVE LAYOUT GET EX 不正确 函数调用 IOCTL DISK      更新时间:2023-10-16

我目前正在尝试编写一个c++程序来自动检索有关示例硬盘驱动器映像的分区的信息,所讨论的信息是磁盘上的分区数量以及每个分区的起始扇区,大小和文件系统类型。

我很确定在这一点上,实现这一点的最好方法是通过MSDN功能,微软内置的命令。我试图使用"IOCTL_DISK_GET_DRIVE_LAYOUT_EX"函数,但根据我的get错误调用,我的函数是不正确的。当我调试程序时,似乎在"IOCTL_DISK_GET_DRIVE_LAYOUT_EX"调用后bool值也没有变化,这意味着它没有返回bResult值。

我使用的是Microsoft Visual c++ Express Edition。如果人们能看一下我的代码,并告诉我他们认为我做错了什么,我将不胜感激。

#define UNICODE 1
#define _UNICODE 1
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#define wszDrive L"\\.\PhysicalDrive6"
BOOL GetDriveParition(LPWSTR wszPath, DRIVE_LAYOUT_INFORMATION_EX *pdg)
{
  HANDLE hDevice = INVALID_HANDLE_VALUE;  // handle to the drive to be examined 
  BOOL bResult   = FALSE;                 // results flag
  DWORD junk     = 0;                     // discard results

  hDevice = CreateFileW(wszPath,          // drive to open
                    0,                // no access to the drive
                    FILE_SHARE_READ | // share mode
                    FILE_SHARE_WRITE, 
                    NULL,             // default security attributes
                    OPEN_EXISTING,    // disposition
                    0,                // file attributes
                    NULL);            // do not copy file attributes
  if (hDevice == INVALID_HANDLE_VALUE)    // cannot open the drive
  {
return (FALSE);
  }
bResult =  DeviceIoControl( 
                  hDevice,                        // handle to device
                  IOCTL_DISK_GET_DRIVE_LAYOUT_EX, // dwIoControlCode
                  NULL,                           // lpInBuffer
                  0,                              // nInBufferSize
                  pdg,                            // lpOutBuffer
                  sizeof(*pdg),                   // nOutBufferSize
                  &junk,                          // lpBytesReturned
                  NULL);                          // lpOverlapped
CloseHandle(hDevice);
return (bResult);

}
int wmain(int argc, wchar_t *argv[])
{
DRIVE_LAYOUT_INFORMATION_EX pdg; // disk drive partition structure
  BOOL bResult = FALSE;      // generic results flag
  bResult = GetDriveParition (wszDrive, &pdg);
  if (bResult) 
  {
    wprintf(L"Drive path            = %wsn",   wszDrive);
    wprintf(L"Partition Style       = %I64dn", pdg.PartitionStyle);
    wprintf(L"Partition Count       = %ldn",   pdg.PartitionCount);
    system("Pause");
  } 
  else 
  {
    wprintf (L"GetDrivePartition failed. Error %ld.n", GetLastError ());
    system("Pause");
  }
  return ((int)bResult);
}

DRIVE_LAYOUT_INFORMATION_EX是一个奇怪的结构。它被定义为

struct {
  DWORD                    PartitionStyle;
  DWORD                    PartitionCount;
  union {
    DRIVE_LAYOUT_INFORMATION_MBR Mbr;
    DRIVE_LAYOUT_INFORMATION_GPT Gpt;
  };
  PARTITION_INFORMATION_EX PartitionEntry[ 1 ];
}

,但通常PartitionEntry被视为一个更大的数组,包含PartitionCount项。这类似于C99 VLA机制。由于只分配了sizeof(*pdg)个字节,因此甚至没有空间容纳第二个PartitionEntry。

c++黑客:

struct ExtraEntries : DRIVE_LAYOUT_INFORMATION_EX
{
   PARTITION_INFORMATION_EX PartitionEntry[ 9 ]; // Or some other reasonable value
};

即使这篇文章有点旧,我也找到了另一种方法来获得一个完全填充的PartitionEntry,而无需创建一个棘手的结构。我是这样做的:

灵感来自这篇文章的答案:how -to-call-deviceiocontrol-to-retrieve-the-amount-of-memory-it- needed

DRIVE_LAYOUT_INFORMATION_EX dli;
DWORD bytesReturned = 0;
if (!DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, (void*)&dli, sizeof(dli), &bytesReturned, NULL))
{
    // Check last error if not ERROR_INSUFFICIENT_BUFFER then return
    int nError = GetLastError();
    if (nError != ERROR_INSUFFICIENT_BUFFER)
    {
        // std::cout << "DeviceIoControl() Failed: " << nError << std::endl;
        CloseHandle(hDevice);
        return false;
    }
    // Allocate enough buffer space based of the value of Partition Count:
    size_t size = offsetof(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[dli.PartitionCount]);
    std::vector<BYTE> buffer(size);
    if (!DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, (void*)buffer.data(), size, &bytesReturned, NULL))
    {
        nError = GetLastError();
        // std::cout << "DeviceIoControl() Failed: " << nError << std::endl;
        CloseHandle(hDevice);
        return false;
    }
    const DRIVE_LAYOUT_INFORMATION_EX& result = *reinterpret_cast<const DRIVE_LAYOUT_INFORMATION_EX*>(buffer.data());
    // Here all parition entry are populated ...
    // TO DO... Do your stuff with result
    
}
else
{
    // Call succeeded; dli is populated with a signle partition entry
    // TO DO... Do your stuff with dli
}