C++ WINAPI 在挂载的 VHD 上创建多个分区

标签 c++ winapi ioctl virtual-disk

我设法创建了一个 VHD 并将其附加。之后,我创建了一个磁盘(IOCTL CREATE_DISK)并使用 IOCTL_DISK_SET_DRIVE_LAYOUT_EX 设置其布局。现在,当我通过磁盘管理检查磁盘时。预计我有一个 14MB 的分区和一个 7MB 的分区。

int sign = 80001;
CREATE_DISK disk;
disk.Mbr.Signature = sign;
disk.PartitionStyle = PARTITION_STYLE_MBR;

auto res = DeviceIoControl(device_handle, IOCTL_DISK_CREATE_DISK, &disk, sizeof(disk), NULL, 0, NULL, NULL);
res = DeviceIoControl(device_handle, IOCTL_DISK_UPDATE_PROPERTIES, 0, 0, NULL, 0, NULL, NULL);

LARGE_INTEGER partition_size;
partition_size.QuadPart = 0xF00;
DWORD driver_layout_ex_len = sizeof(DRIVE_LAYOUT_INFORMATION_EX);
DRIVE_LAYOUT_INFORMATION_EX driver_layout_info;
memset(&driver_layout_info, 0, sizeof(DRIVE_LAYOUT_INFORMATION_EX));

driver_layout_info.Mbr.Signature = sign;
driver_layout_info.PartitionCount = 1;
driver_layout_info.PartitionStyle = PARTITION_STYLE_MBR;

PARTITION_INFORMATION_EX part_info;
PARTITION_INFORMATION_MBR mbr_info;
part_info.StartingOffset.QuadPart = 32256;
part_info.RewritePartition = TRUE;
part_info.PartitionLength.QuadPart = partition_size.QuadPart/2 * 4096;
part_info.PartitionNumber = 1;
part_info.PartitionStyle = PARTITION_STYLE_MBR;

mbr_info.BootIndicator = TRUE;
mbr_info.HiddenSectors = 32256 / 512;
mbr_info.PartitionType = PARTITION_FAT32;
mbr_info.RecognizedPartition = 1;
part_info.Mbr = mbr_info;
driver_layout_info.PartitionEntry[0] = part_info;
auto res_layout = DeviceIoControl(device_handle, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, &driver_layout_info, sizeof(driver_layout_info), NULL, 0, NULL, NULL);

现在,我如何将这个磁盘分成两个分区?我想从磁盘的未分区部分(基本上是另一半)创建另一个分区。它在文档中说 PartitionEntry 是一个可变大小的数组(不,它不是一个大小为 1 的数组。)我是否为我想创建的每个分区调用 set layout IOCTL?如果是这样,您将如何处理?是否可以通过 WINAPI 接口(interface)进行多分区?

P.S:我知道人们通常会为这行工作调用 diskpart。

编辑: 添加第二个分区两个布局搞乱了我的堆栈,所以我选择了另一条路线(堆)。

DWORD driver_layout_ex_len = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX); // one layout+partition + partition
PDRIVE_LAYOUT_INFORMATION_EX driver_layout_info = (PDRIVE_LAYOUT_INFORMATION_EX) std::calloc(1, driver_layout_ex_len);

driver_layout_info->Mbr.Signature = sign;
driver_layout_info->PartitionCount = 2;
driver_layout_info->PartitionStyle = PARTITION_STYLE_MBR;
// omitted here..
PARTITION_INFORMATION_EX part_info2;
part_info2.StartingOffset.QuadPart = 32256 + part_info.PartitionLength.QuadPart;
part_info2.RewritePartition = TRUE;
part_info2.PartitionLength.QuadPart = partition_size.QuadPart / 2 * 4096;
part_info2.PartitionNumber = 2;
part_info2.PartitionStyle = PARTITION_STYLE_MBR;

part_info2.Mbr = mbr_info;


driver_layout_info->PartitionEntry[0] = part_info;
driver_layout_info->PartitionEntry[1] = part_info2;
auto res_layout = DeviceIoControl(device_handle, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, driver_layout_info, driver_layout_ex_len, NULL, 0, NULL, NULL);
auto res_err = GetLastError(); 

因为它覆盖了我的 device_handle 我根本无法使用 IOCTL。这种改进消除了这一点。不要忘记在此更改后传递 driver_layout_info 而不是 &driver_layout_info。

最佳答案

It says in the documentation is that PartitionEntry is an array of variable size(No, it is not it is an array of size 1.)

“一些 Windows 结构是可变大小的, 以固定标题开头,然后是 可变大小的数组。当这些结构 被宣布, 他们经常声明一个大小为 1 的数组,其中 可变大小的数组应该是。”请参阅 @Raymond blog

在这里DRIVE_LAYOUT_INFORMATION_EX structure是一个例子:

typedef struct _DRIVE_LAYOUT_INFORMATION_EX {
  DWORD                    PartitionStyle;
  DWORD                    PartitionCount;
  union {
    DRIVE_LAYOUT_INFORMATION_MBR Mbr;
    DRIVE_LAYOUT_INFORMATION_GPT Gpt;
  } DUMMYUNIONNAME;
  PARTITION_INFORMATION_EX PartitionEntry[1];
} DRIVE_LAYOUT_INFORMATION_EX, *PDRIVE_LAYOUT_INFORMATION_EX;

使用此声明,您将为这样的一个分配内存 可变大小的 DRIVE_LAYOUT_INFORMATION_EX 结构如下:

PDRIVE_LAYOUT_INFORMATION_EX driver_layout_info = (PDRIVE_LAYOUT_INFORMATION_EX)malloc(FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[NumberOfPartitions]));

您可以像这样初始化结构(以 2 个分区为例):

DWORD NumberOfPartitions = 2;
LARGE_INTEGER partition_size;
partition_size.QuadPart = 0xF00;

PARTITION_INFORMATION_MBR mbr_info;
mbr_info.BootIndicator = TRUE;
mbr_info.HiddenSectors = 32256 / 512;
mbr_info.PartitionType = PARTITION_FAT32;
mbr_info.RecognizedPartition = TRUE;

PDRIVE_LAYOUT_INFORMATION_EX driver_layout_info = (PDRIVE_LAYOUT_INFORMATION_EX)malloc(FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[NumberOfPartitions]));
for (DWORD Index = 0; Index < NumberOfPartitions ; Index++) {

    driver_layout_info->PartitionEntry[Index].PartitionStyle = PARTITION_STYLE_MBR;
    driver_layout_info->PartitionEntry[Index].PartitionNumber = Index + 1;
    driver_layout_info->PartitionEntry[Index].RewritePartition = TRUE;
    driver_layout_info->PartitionEntry[Index].PartitionLength.QuadPart = partition_size.QuadPart / 2 * 4096;
    driver_layout_info->PartitionEntry[Index].Mbr = mbr_info;
}

driver_layout_info->Mbr.Signature = sign;
driver_layout_info->PartitionCount = 1;
driver_layout_info->PartitionStyle = PARTITION_STYLE_MBR;

driver_layout_info->PartitionEntry[0].StartingOffset.QuadPart = 32256;
driver_layout_info->PartitionEntry[1].StartingOffset.QuadPart = 32256 + driver_layout_info->PartitionEntry->StartingOffset.QuadPart;

DWORD driver_layout_ex_len = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX);

使用完毕后调用free(driver_layout_info);

关于C++ WINAPI 在挂载的 VHD 上创建多个分区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56774073/

相关文章:

c++ - Visual Studio 2010 C++ 中 win32form 上的控制台应用程序输出

c# - 如何使用 swig 从 `uint []` 返回 `unsigned int *`

C++ Win32 API 控制消息

c++ - win32 - 在按钮中使用默认按钮字体

unix - sendto的最大缓冲区长度?

c - 如何使用 inet_pton 和 struct ifreq 从 C 程序设置 ip 地址

c++ - 对齐数据类型 Eigen::Matrix 的数组或 vector 声明

c++ - 在 UI 线程上运行代码

c++ - 从无窗口控件获取文本

linux - 为什么系统调用的次数非常有限?