c++ - C++ WINAPI 在挂载的 VHD 上创建多个分区
问题描述
我设法创建了一个 VHD 并附加了它。之后,我创建了一个磁盘(IOCTL CREATE_DISK)并使用 IOCTL_DISK_SET_DRIVE_LAYOUT_EX 设置它的布局。现在,当我通过磁盘管理检查磁盘时。预计我有一个 14MB 和 7 MB 的分区。
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 接口进行多分区?
PS:我知道人们通常会为这行工作调用 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。
解决方案
它在文档中说 PartitionEntry 是一个可变大小的数组(不,它不是一个大小为 1 的数组。)
“一些 Windows 结构是可变大小的,从一个固定的标头开始,然后是一个可变大小的数组。在声明这些结构时,它们通常会声明一个大小为 1 的数组,而可变大小的数组应该是。” 请参阅@Raymond 博客。
这里DRIVE_LAYOUT_INFORMATION_EX 结构是一个例子:
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);
用完后打电话。
推荐阅读
- visual-studio - SSIS 自定义任务错误 - 代码:0xC001F02A 源:包描述:无法从 XML 为任务创建任务
- sass - 在sass中,用@use替换@import而不是扩展变量
- c++ - 检查模板参数的类型并使用另一个模板
- node.js - 如何在电子的 web 视图中创建上下文菜单
- html - 需要修复电子邮件签名中的水平线
- winapi - 有谁知道如何使用 Zip Utils 将给定目录的文件夹及其内容添加到 zip 文件中?
- clojure - Clojure在地图中添加键
- java - SFTP 上传的方法中 session.connect() 中的问题
- javascript - 如何在 IntelliJ/WebStorm 中跳转到导入的 JavaScript 文件
- vba - 循环遍历 Excel 工作簿文件夹并仅将带有关键字的工作簿附加到主工作表