大家好,欢迎来到IT知识分享网。
上一节中我们介绍了一些基本概念和主要的API,本节开始我们将列举并分析一些实例。本文中的所有代码我都在vs2008下测试过,读者只需要替换少量的宏定义即可编译执行。
面对一块新的磁盘,我们首先要做的就是对其初始化。在系统中通过windows
的磁盘管理完成这一点非常容易,但在程序中实现略微复杂。本节的示例代码对一块新硬盘初始化,并在上面创建分区。
的磁盘管理完成这一点非常容易,但在程序中实现略微复杂。本节的示例代码对一块新硬盘初始化,并在上面创建分区。
代码如下:
/
* Function: initialize the disk and create partitions
* input: disk, disk name
* parNum, partition number
* output: N/A
* return: Succeed, 0
* Fail, -1
/
DWORD CreateDisk(DWORD disk, WORD partNum)
{
HANDLE hDevice; // handle to the drive to be examined
BOOL result; // results flag
DWORD readed; // discard results
DWORD ret;
WORD i;
CHAR diskPath[DISK_PATH_LEN];
DISK_GEOMETRY pdg;
DWORD sectorSize;
DWORD signature;
LARGE_INTEGER diskSize;
LARGE_INTEGER partSize;
BYTE actualPartNum;
DWORD layoutStructSize;
DRIVE_LAYOUT_INFORMATION_EX *dl;
CREATE_DISK newDisk;
sprintf(diskPath, “\\\\.\\PhysicalDrive%d”, disk);
actualPartNum = 4;
if (partNum > actualPartNum)
{
return (WORD)-1;
}
hDevice = CreateFile(
diskPath,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, //default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL
);
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
fprintf(stderr, “CreateFile() Error: %ld\n”, GetLastError());
return DWORD(-1);
}
// Create primary partition MBR
newDisk.PartitionStyle = PARTITION_STYLE_MBR;
signature = (DWORD)time(NULL); //get signature from current time
newDisk.Mbr.Signature = signature;
result = DeviceIoControl(
hDevice,
IOCTL_DISK_CREATE_DISK,
&newDisk,
sizeof(CREATE_DISK),
NULL,
0,
&readed,
NULL
);
if (!result)
{
fprintf(stderr, “IOCTL_DISK_CREATE_DISK Error: %ld\n”, GetLastError());
(void)CloseHandle(hDevice);
return DWORD(-1);
}
//fresh the partition table
result = DeviceIoControl(
hDevice,
IOCTL_DISK_UPDATE_PROPERTIES,
NULL,
0,
NULL,
0,
&readed,
NULL
);
if (!result)
{
fprintf(stderr, “IOCTL_DISK_UPDATE_PROPERTIES Error: %ld\n”, GetLastError());
(void)CloseHandle(hDevice);
return DWORD(-1);
}
//Now create the partitions
ret = GetDriveGeometry(diskPath, &pdg);
if ((DWORD)-1 == ret)
{
return ret;
}
sectorSize = pdg.BytesPerSector;
diskSize.QuadPart = pdg.Cylinders.QuadPart * pdg.TracksPerCylinder *
pdg.SectorsPerTrack * pdg.BytesPerSector; //calculate the disk size;
partSize.QuadPart = diskSize.QuadPart / partNum;
layoutStructSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (actualPartNum – 1) * sizeof(PARTITION_INFORMATION_EX);
dl = (DRIVE_LAYOUT_INFORMATION_EX*)malloc(layoutStructSize);
if (NULL == dl)
{
(void)CloseHandle(hDevice);
return (WORD)-1;
}
dl->PartitionStyle = (DWORD)PARTITION_STYLE_MBR;
dl->PartitionCount = actualPartNum;
dl->Mbr.Signature = signature;
//clear the unused partitions
for (i = 0; i < actualPartNum; i++){
dl->PartitionEntry[i].RewritePartition = 1;
dl->PartitionEntry[i].Mbr.PartitionType = PARTITION_ENTRY_UNUSED;
}
//set the profile of the partitions
for (i = 0; i < partNum; i++){
dl->PartitionEntry[i].PartitionStyle = PARTITION_STYLE_MBR;
dl->PartitionEntry[i].StartingOffset.QuadPart =
(partSize.QuadPart * i) + ((LONGLONG)(pdg.SectorsPerTrack) * (LONGLONG)(pdg.BytesPerSector)); //32256
dl->PartitionEntry[i].PartitionLength.QuadPart = partSize.QuadPart;
dl->PartitionEntry[i].PartitionNumber = i + 1;
dl->PartitionEntry[i].RewritePartition = TRUE;
dl->PartitionEntry[i].Mbr.PartitionType = PARTITION_IFS;
dl->PartitionEntry[i].Mbr.BootIndicator = FALSE;
dl->PartitionEntry[i].Mbr.RecognizedPartition = TRUE;
dl->PartitionEntry[i].Mbr.HiddenSectors =
pdg.SectorsPerTrack + (DWORD)((partSize.QuadPart / sectorSize) * i);
}
//execute the layout
result = DeviceIoControl(
hDevice,
IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
dl,
layoutStructSize,
NULL,
0,
&readed,
NULL
);
if (!result)
{
fprintf(stderr, “IOCTL_DISK_SET_DRIVE_LAYOUT_EX Error: %ld\n”, GetLastError());
free(dl);
(void)CloseHandle(hDevice);
return DWORD(-1);
}
//fresh the partition table
result = DeviceIoControl(
hDevice,
IOCTL_DISK_UPDATE_PROPERTIES,
NULL,
0,
NULL,
0,
&readed,
NULL
);
if (!result)
{
fprintf(stderr, “IOCTL_DISK_UPDATE_PROPERTIES Error: %ld\n”, GetLastError());
free(dl);
(void)CloseHandle(hDevice);
return DWORD(-1);
}
free(dl);
(void)CloseHandle(hDevice);
Sleep(3000); //wait the operations take effect
return 0;
}
函数
CreateDisk
包含两个参数,
CreateDisk
包含两个参数,
DWORD disk
填入物理驱动器号,参见第一节。
填入物理驱动器号,参见第一节。
WORD partNum
表示需要创建的分区数,
partNum <= 4
。
表示需要创建的分区数,
partNum <= 4
。
函数的执行流程解释如下:
/*
初始化磁盘*/
初始化磁盘*/
1.
根据disk
创建设备名称,\\\\.\\PhysicalDriveX
,这里由于要转义,所以”\”
都写为”\\”
。
根据disk
创建设备名称,\\\\.\\PhysicalDriveX
,这里由于要转义,所以”\”
都写为”\\”
。
2.
调用CreateFile
打开设备文件,并获得句柄。
调用CreateFile
打开设备文件,并获得句柄。
3.
用操作码
IOCTL_DISK_CREATE_DISK
调用
DeviceIoControl
函数,初始化磁盘并创建分区表。
用操作码
IOCTL_DISK_CREATE_DISK
调用
DeviceIoControl
函数,初始化磁盘并创建分区表。
使用
IOCTL_DISK_CREATE_DISK
操作码时,lpInBuffer
要填入一个
CREATE_DISK
结构参数,其中包括分区表类型和磁盘签名等参数,详见MSDN
。本例中创建MBR
分区表,签名由当前时间产生。
IOCTL_DISK_CREATE_DISK
操作码时,lpInBuffer
要填入一个
CREATE_DISK
结构参数,其中包括分区表类型和磁盘签名等参数,详见MSDN
。本例中创建MBR
分区表,签名由当前时间产生。
4.
刷新分区表。注意,程序中任何时候对磁盘的分区信息进行了修改都需要调用操作码为
IOCTL_DISK_UPDATE_PROPERTIES
的
DeviceIoControl
函数来刷新分区表,是操作切实生效。
刷新分区表。注意,程序中任何时候对磁盘的分区信息进行了修改都需要调用操作码为
IOCTL_DISK_UPDATE_PROPERTIES
的
DeviceIoControl
函数来刷新分区表,是操作切实生效。
/
创建分区*/
创建分区*/
5.
调用
GetDriveGeometry
获取磁盘信息(GetDriveGeometry
参见上一节http://cutebunny.blog.51cto.com//)。由于创建分区时要填入分区大小信息,我们此处先计算磁盘总大小,然后除以partNum
将字节数平均分配到各个分区。
调用
GetDriveGeometry
获取磁盘信息(GetDriveGeometry
参见上一节http://cutebunny.blog.51cto.com//)。由于创建分区时要填入分区大小信息,我们此处先计算磁盘总大小,然后除以partNum
将字节数平均分配到各个分区。
6.
分配
DRIVE_LAYOUT_INFORMATION_EX
结构体空间。我们通过在这个结构体中填入数据来指定如何对硬盘进行分区。结构体定义如下
分配
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;
};
PARTITION_INFORMATION_EX PartitionEntry[1];
} DRIVE_LAYOUT_INFORMATION_EX,
*PDRIVE_LAYOUT_INFORMATION_EX;
其中
PartitionCount
为4
的倍数,为简化处理,我们这里定死为4
。
另外还要注意
PARTITION_INFORMATION_EX
型的数组
PartitionEntry[1]
。虽然结构体中只定义了一个元素,但事实上必须在其后补足PartitionCount – 1
个元素。所以代码中为DRIVE_LAYOUT_INFORMATION_EX *dl
分配空间的时候加上了(actualPartNum – 1) * sizeof(PARTITION_INFORMATION_EX)
。
7.
在
DRIVE_LAYOUT_INFORMATION_EX
结构体空间dl
中填入数据。
在
DRIVE_LAYOUT_INFORMATION_EX
结构体空间dl
中填入数据。
先将所有分区都设为
PARTITION_ENTRY_UNUSED
,后面具体分配多少个分区再设置回来。
PARTITION_ENTRY_UNUSED
,后面具体分配多少个分区再设置回来。
然后再循环体内对每个分区的PartitionEntry
赋值,其中
赋值,其中
StartingOffset
除了跳过前面的分区已占据的空间外,还要加上63
个扇区空间(32256
字节)。
除了跳过前面的分区已占据的空间外,还要加上63
个扇区空间(32256
字节)。
PartitionNumber
从1
开始。
从1
开始。
Mbr.PartitionType = PARTITION_IFS
表示NTFS
格式。
表示NTFS
格式。
Mbr.HiddenSectors MSDN
上说The number of hidden sectors to be allocated when the partition table is created.
我理解得不是很深刻,欢迎补充。
上说The number of hidden sectors to be allocated when the partition table is created.
我理解得不是很深刻,欢迎补充。
8.
调用操作码为
IOCTL_DISK_SET_DRIVE_LAYOUT_EX
的
DeviceIoControl
函数执行分区,参数需要填入刚才准备好的
DRIVE_LAYOUT_INFORMATION_EX
结构体和大小。
调用操作码为
IOCTL_DISK_SET_DRIVE_LAYOUT_EX
的
DeviceIoControl
函数执行分区,参数需要填入刚才准备好的
DRIVE_LAYOUT_INFORMATION_EX
结构体和大小。
9.
刷新分区表,原理同4
。
刷新分区表,原理同4
。
另外,我在函数末尾加上了Sleep(3000)
。这是因为我发现创建分区操作需要一定的执行时间,如果后续紧跟着其它相关操作(例如格式化该分区)可能会产生分区不存在的错误,所以此处等待3
秒确保其执行完毕。
。这是因为我发现创建分区操作需要一定的执行时间,如果后续紧跟着其它相关操作(例如格式化该分区)可能会产生分区不存在的错误,所以此处等待3
秒确保其执行完毕。
本节涉及的类型较多,但各类型具有很强的关联性,读者可随时查阅MSDN获得更详细的说明。
本文出自 “bunny技术坊” 博客,请务必保留此出处http://cutebunny.blog.51cto.com//
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/129605.html