广州找人做网站,大连seo皮皮,商城系统源码,微网站样式简单介绍使用vds.h中的类和方法操作修改硬件/盘符的一些常使用的结构和函数#xff0c;包括获取格式、删除、创建分区#xff0c;设置磁盘文件类型#xff0c;格式化卷等#xff1b; 值得注意的是即使在vds.h库中像格式化卷这种都有多个方法#xff0c;需要根据实际需求选… 简单介绍使用vds.h中的类和方法操作修改硬件/盘符的一些常使用的结构和函数包括获取格式、删除、创建分区设置磁盘文件类型格式化卷等 值得注意的是即使在vds.h库中像格式化卷这种都有多个方法需要根据实际需求选择合适的方法。 目录导读 提示VDS服务是否能使用磁盘操作打开使用 CreateFile 函数创建磁盘对象的句柄获取磁盘设计大小格式分区创建分区使用 IOCTL_DISK_SET_DRIVE_LAYOUT_EX 创建分区(推荐)使用 IVdsCreatePartitionEx 接口 创建分区 卷操作获取卷列表打开使用 CreateFile 函数创建卷对象的句柄获取卷关联的磁盘获取卷的驱动器号获取卷名称或文件系统名称获取卷上剩余空间/卷大小等信息格式化卷 提示
在对磁盘和卷进行处理时建议简单了解他们之间的关系可以参考 【Windows系统】磁盘、Partition和Volume的联系与区别 本文涉及的部分类和函数优先参考 Qt案例 使用WINDOWS API的VDS.H库查询/修改 WINDOWS系统中硬盘分区/盘符信息(一) 一文中的IVdsDisk 接口和IVdsVolume 接口的声明基础上使用 注意不要用有重要数据的磁盘/分区来进行测试。容易造成数据丢失
VDS服务是否能使用
在部分精简系统或者阉割系统中是不会包含vds服务需要简单判断是否支持vds服务以便于后续操作。
bool IsVDSAvailable()
{IVdsService* pService NULL;IVdsServiceLoader* pLoader NULL;HRESULT hr CoCreateInstance(CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,IID_IVdsServiceLoader, (void**)pLoader);if (hr ! S_OK) {qDebug(Notice: Disabling VDS (Could not create VDS Loader Instance: %s), WindowsError::GetVdsError(hr));goto out;}hr pLoader-LoadService( L, pService);if (hr ! S_OK) {qDebug(Notice: Disabling VDS (Could not load VDS Service: %s), WindowsError::GetVdsError(hr));goto out;}out:if (pService ! NULL)pService-Release();if (pLoader ! NULL)pLoader-Release();return (hr S_OK);
}磁盘操作
打开使用 CreateFile 函数创建磁盘对象的句柄
通过VDS_DISK_PROP结构可以获取pwszName打开磁盘操作对象句柄
//pwszName : \\?\PhysicalDrive2HANDLE hDrive INVALID_HANDLE_VALUE;hDrive CreateFileW(prop.pwszName, GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if(hDriveINVALID_HANDLE_VALUE){continue;}
获取磁盘设计大小
使用 DISK_GEOMETRY_EX 结构 描述磁盘设备和介质的扩展几何结构获取磁盘设计大小。 可用获取 DISK_GEOMETRY 结构 获取磁盘的 Cylinders(柱面数)。 磁盘设计大小柱面数*每个柱面的轨道数*每个轨道的扇区数*每个扇区字节数 DiskSize Cylinders*TracksPerCylinder*SectorsPerTrack*BytesPerSector BYTE geometry[256] {0};PDISK_GEOMETRY_EX DiskGeometry (PDISK_GEOMETRY_EX)(void*)geometry;DWORD size0;if(!DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,NULL, 0, geometry, sizeof(geometry), size, NULL)||size0){CloseHandle(hDrive);continue;}//qDebug()柱面数量: QString::number(DiskGeometry-Geometry.Cylinders.QuadPart,10);格式分区
使用IVdsAdvancedDisk::FormatPartition方法格式化创建好的分区此方法仅设置 OEM、ESP 和未知分区的格式如果是其他分区需要根据磁盘分区偏移量找到对应的卷然后使用 IVdsVolumeMF::Format 或 IVdsVolumeMF2::FormatEx 方法格式化相应的卷。这样磁盘分区才能正常使用计算机管理-》磁盘管理才会正常显示分区
/*
//!.hVDS 实现此方法。此方法仅设置 OEM、ESP 和未知分区的格式。对于其他分区必须使用 IVdsVolumeMFFormat 或 IVdsVolumeMF2FormatEx 方法格式化相应的卷。请注意OEM、ESP 和未知分区不会作为卷公开因此不能使用 Format 或 FormatEx 进行格式化。此方法不能用于格式化可移动媒体。*//// The operation is not supported on removable media/// \brief D_FormatPartition 设置现有 OEM、ESP 或未知分区的格式。/// \param _ullOffset 分区偏移量。/// \param _type [VDS_FST_NTFS、VDS_FST_FAT、VDS_FST_FAT32或VDS_FST_UDF]/// \param _pwszLabel 表示卷标签的字符串。/// \param _dwUnitAllocationSize 文件系统分配单元的大小以字节为单位/// \param _bForce 如果为 TRUE则即使正在使用分区分区也会格式化/// \param _bQuickFormat 如果为 TRUE则 VDS 执行快速格式/// \param _bEnableCompression 如果为TRUE则对新格式化的文件系统启用压缩 不能为 FAT 和 FAT32 文件系统设置压缩/// \return///bool D_FormatPartition( ULONGLONG _ullOffset,VDS_FILE_SYSTEM_TYPE _type,LPWSTR _pwszLabel,DWORD _dwUnitAllocationSize,BOOL _bForcetrue,BOOL _bQuickFormattrue,BOOL _bEnableCompressionfalse);//!.Cpp
bool D_FormatPartition( ULONGLONG _ullOffset,VDS_FILE_SYSTEM_TYPE _type,LPWSTR _pwszLabel,DWORD _dwUnitAllocationSize,BOOL _bForce,BOOL _bQuickFormat,BOOL _bEnableCompression)
{bool resultfalse;//pAdvancedDisk 是 IVdsAdvancedDisk 接口的具体实例IVdsAsync* pAsyncNULL;ULONG ulPercentCompleted0;HRESULT hResult pAdvancedDisk-FormatPartition( _ullOffset, _type, _pwszLabel, _dwUnitAllocationSize,_bForce,_bQuickFormat, _bEnableCompression,pAsync);ULONG jindu0;while (SUCCEEDED(hResult)) {if (IS_ERROR(hResult)) {pAsync-Cancel();break;}HRESULT hresult2;hResult pAsync-QueryStatus( hresult2, ulPercentCompleted);if (SUCCEEDED(hResult)) {hResulthresult2;if (hResult S_OK)break;if (hResult VDS_E_OPERATION_PENDING)hResult S_OK;}if(jindu!ulPercentCompleted){jinduulPercentCompleted;qDebug() schedule : jindu;}if(ulPercentCompleted100)break;}result(hResultS_OK);if(!result)qDebug()pAdvancedDisk Clean is failed! WindowsError::GetVdsError(hResult);out:return result;
}创建分区
使用 IOCTL_DISK_SET_DRIVE_LAYOUT_EX 创建分区(推荐)
IOCTL_DISK_SET_DRIVE_LAYOUT_EX 按指定对磁盘进行重新分区。 推荐使用这种方式格式化分区直接可以同时创建多个分区唯一需要注意的是 需要简单修改 DRIVE_LAYOUT_INFORMATION_EX 结构体
/* MinGW is unhappy about accessing partitions beside the first unless we redef */
//! MinGW不喜欢访问第一个分区之外的分区除非我们重新定义
typedef struct _DRIVE_LAYOUT_INFORMATION_EX4 {DWORD PartitionStyle;DWORD PartitionCount;union {DRIVE_LAYOUT_INFORMATION_MBR Mbr;DRIVE_LAYOUT_INFORMATION_GPT Gpt;} Type;PARTITION_INFORMATION_EX PartitionEntry[16];
} DRIVE_LAYOUT_INFORMATION_EX4, *PDRIVE_LAYOUT_INFORMATION_EX4;
调用: LONGLONG ullSize1215277056;///设置后方分区大小LONGLONG ullSize2373588*prop.ulBytesPerSector;LONGLONG ullOffsetDiskUllSize-ullSize;CREATE_DISK CreateDisk {PARTITION_STYLE_MBR, {{0}}};CreateDisk.PartitionStylePARTITION_STYLE_MBR;CreateDisk.Mbr.Signature(DWORD)GetTickCount64();DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx {0};DriveLayoutEx.PartitionStylePARTITION_STYLE_MBR;DriveLayoutEx.PartitionCount2;DriveLayoutEx.PartitionEntry[0].PartitionStylePARTITION_STYLE_MBR;DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPartullOffset;DriveLayoutEx.PartitionEntry[0].PartitionLength.QuadPartullSize;DriveLayoutEx.PartitionEntry[0].PartitionNumber1;DriveLayoutEx.PartitionEntry[0].RewritePartitionTRUE;DriveLayoutEx.PartitionEntry[0].Mbr.BootIndicatorTRUE;DriveLayoutEx.PartitionEntry[0].Mbr.PartitionType0xef;DriveLayoutEx.PartitionEntry[0].Mbr.RecognizedPartitionTRUE;//设置中间间隔LONGLONG Offset(2048*prop.ulBytesPerSector);//设置分区大小LONGLONG OffullSizeDiskUllSize-ullSize-Offset;DriveLayoutEx.PartitionEntry[1].PartitionStylePARTITION_STYLE_MBR;DriveLayoutEx.PartitionEntry[1].StartingOffset.QuadPartOffset;DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPartOffullSize;DriveLayoutEx.PartitionEntry[1].PartitionNumber2;DriveLayoutEx.PartitionEntry[1].RewritePartitionTRUE;DriveLayoutEx.PartitionEntry[1].Mbr.BootIndicatorTRUE;DriveLayoutEx.PartitionEntry[1].Mbr.PartitionType0xef;DriveLayoutEx.PartitionEntry[1].Mbr.RecognizedPartitionTRUE;DriveLayoutEx.Type.Mbr.Signature CreateDisk.Mbr.Signature;//hDrive 磁盘对象句柄DWORD size sizeof(CreateDisk);//!如果不调用IOCTL_DISK_CREATE_DISK, IOCTL_DISK_SET_DRIVE_LAYOUT_EX调用将失败bool r DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, (BYTE*)CreateDisk, size, NULL, 0, size, NULL);if (!r) {qDebug()Could not reset disk: %s GetError();return ;}RefreshDriveLayout();sizesizeof(DriveLayoutEx);r DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)DriveLayoutEx, size, NULL, 0, size, NULL);if (!r) {qDebug()Could not set drive layout: GetError();return ;}RefreshDriveLayout();使用 IVdsCreatePartitionEx 接口 创建分区
IVdsCreatePartitionEx 接口 在基本磁盘上创建分区。 IVdsCreatePartitionEx::CreatePartitionEx 在基本磁盘上创建分区。 IVdsCreatePartitionEx 接口实例需要通过IVdsDisk 接口获取。
初始化实例 IVdsCreatePartitionEx* pCreatePartitionNULL;//判断 IVdsDisk 接口 接口实例是否有效//IFNULL_GOTO(pDisk,pDisk No instantiation!,out);HRESULT hResult pDisk-QueryInterface(IID_IVdsCreatePartitionEx,(void **)pCreatePartition);if (hResult ! S_OK){qDebug(Could not initialize_pCreatePartition : %s, GetLastError());pCreatePartitionNULL;}
创建分区:
/// 如果起始分区不在第一柱形内分区后的分区偏移量会发生偏适用于创建一个分区差/// \brief 在基本磁盘上创建分区。 [此方法取代 IVdsAdvancedDiskCreatePartition 方法。]/// *当调用方同时指定 ullOffset 和 ulAlign 参数时偏移量必须位于第一个柱形内*。/// \param _ullOffset 分区偏移量/// \param _ullSize 新分区的大小以字节为单位/// \param _ulAlign 对齐大小以字节为单位。/// \param para gpt/mbr/// \return///bool CreatePartitionEx(ULONGLONG _ullOffset,ULONGLONG _ullSize,ULONG _ulAlign,CREATE_PARTITION_PARAMETERS *para);bool resultfalse;//判断IVdsCreatePartitionEx 接口是否有效 //IFNULL_INIT_ISNULL_GOTO(pCreatePartition,initialize_pCreatePartition(),pCreatePartition No instantiation! ,out);IVdsAsync* pAsyncNULL;ULONG ulPercentCompleted;HRESULT hResult pCreatePartition-CreatePartitionEx(_ullOffset,_ullSize,_ulAlign,para,pAsync);ULONG jindu0;while (SUCCEEDED(hResult)) {if (IS_ERROR(hResult)) {pAsync-Cancel();break;}HRESULT hresult2;hResult pAsync-QueryStatus( hresult2, ulPercentCompleted);if (SUCCEEDED(hResult)) {hResulthresult2;if (hResult S_OK)break;if (hResult VDS_E_OPERATION_PENDING)hResult S_OK;}if(jindu!ulPercentCompleted){jinduulPercentCompleted;qDebug() schedule : jindu;}if(ulPercentCompleted100)break;}result(hResultS_OK);///if(!result)/// qDebug()pCreatePartition CreatePartitionEx is failed! WindowsError::GetVdsError(hResult);注意如果起始分区偏移量不在第一柱形内分区后的分区偏移量会发生偏移 一般磁盘的一个扇区512字节,一个柱面有255个轨道每个轨道63个扇区 所以第一个分区的起始偏移量不能超过 1*255*63*512 字节 发生偏移后就没办法准确获取对应的卷进行格式化不推荐使用。
卷操作
获取卷列表
通过FindFirstVolume 扫描计算机的卷。 FindFirstVolume 函数打开卷搜索句柄并返回有关在计算机上找到的第一个卷的信息。 建立搜索句柄后可以使用 FindNextVolume 函数搜索其他卷。 如果不再需要搜索句柄请使用 FindVolumeClose 函数将其关闭。
HANDLE hDrive INVALID_HANDLE_VALUE, hVolume INVALID_HANDLE_VALUE;
wchar_t * volume_name[MAX_PATH], path[MAX_PATH];for(uint32_t i0; true; i){if (i 0) {hVolume FindFirstVolumeW((LPWSTR)volume_name, sizeof(volume_name));if (hVolume INVALID_HANDLE_VALUE) {qDebug(Could not access first GUID volume);goto out;}} else {if (!FindNextVolumeW(hVolume, (LPWSTR)volume_name, sizeof(volume_name))) {if (GetLastError() ! ERROR_NO_MORE_FILES) {qDebug(Could not access next GUID volume);}qDebug()FindNextVolumeW is failed!;break;}}QString volume_dQString::fromWCharArray((LPCWSTR)volume_name);qDebug()[volume_d] volume_d;
}
打开使用 CreateFile 函数创建卷对象的句柄
通过 volume_name 打开卷对象句柄 [volume_d] \\\\?\\Volume{2efb2ac5-6828-4320-8848-041647908928}\\ QString volume_dQString::fromWCharArray((LPCWSTR)volume_name);hDrive CreateFileW((LPCWSTR)volume_d.mid(0,volume_d.length()-1).toStdWString().c_str(), GENERIC_READ|FILE_READ_ATTRIBUTES|SYNCHRONIZE|FILE_TRAVERSE,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);if (hDrive INVALID_HANDLE_VALUE) {qDebug(Could not open GUID volume %s, volume_name);continue;}获取卷关联的磁盘
VOLUME_DISK_EXTENTS 结构 表示磁盘上的物理位置可通过此结构获取卷对应的磁盘。经常使用。
///重构结构体
typedef struct _VOLUME_DISK_EXTENTS_OverDide {DWORD NumberOfDiskExtents;// Set ANYSIZE_ARRAY 8DISK_EXTENT Extents[8];
} VOLUME_DISK_EXTENTS_OverDide;VOLUME_DISK_EXTENTS_OverDide DiskExtents;DWORD size0;//hDrive 卷对象句柄bool r DeviceIoControl(hDrive, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0,DiskExtents, sizeof(DiskExtents), size, NULL);if ((!r) || (size 0)) {qDebug(Could not get Disk Extents: (empty data)!);if(hDrive!NULL)CloseHandle(hDrive);continue;}if (DiskExtents.NumberOfDiskExtents 0) {qDebug(Ignoring volume %s because it has no extents..., volume_name);continue;}if (DiskExtents.NumberOfDiskExtents ! 1) {// If we have more than one extent for a volume, it means that someone// is using RAID-1 or something Stay well away from such a volume!qDebug(Ignoring volume %s because it has more than one extent (RAID?)..., volume_name);continue;}
// DiskExtents.Extents[0].DiskNumber 磁盘索引//if (DiskExtents.Extents[0].DiskNumber ! Deive_item.DeviceNumber)// Not on our disk// continue;获取卷的驱动器号
getVolumePathNamesForVolumeNameW 函数 检索指定卷的驱动器号和装载的文件夹路径的列表。 DWORD CharCount MAX_PATH 1;PWCHAR Names (PWCHAR) new BYTE [CharCount * sizeof(WCHAR)];bool Success GetVolumePathNamesForVolumeNameW((LPCWSTR)volume_name, Names, CharCount, CharCount);if ( !Success )continue;
// qDebug()[Names] : QString::fromWCharArray(Names);获取卷名称或文件系统名称
getVolumeInformationByHandleW 函数 检索与指定文件关联的文件系统和卷的相关信息。 LPCWSTR lpRootPathName(LPCWSTR)Names;DWORD nVolumeNameSizeMAX_PATH1;LPWSTR lpVolumeNameBuffer(LPWSTR)new BYTE [nVolumeNameSize * sizeof(WCHAR)];LPDWORD lpVolumeSerialNumber0;LPDWORD lpMaximumComponentLength0;LPDWORD lpFileSystemFlags0;DWORD nFileSystemNameSizeMAX_PATH1;LPWSTR lpFileSystemNameBuffer(LPWSTR)new BYTE [nFileSystemNameSize * sizeof(WCHAR)];BOOL ishave GetVolumeInformationByHandleW(hDrive,lpVolumeNameBuffer,nVolumeNameSize,lpVolumeSerialNumber,lpMaximumComponentLength,lpFileSystemFlags,lpFileSystemNameBuffer,nFileSystemNameSize);if(!ishave)continue;qDebug()[lpVolumeNameBuffer] : QString::fromWCharArray(lpVolumeNameBuffer);qDebug()[lpFileSystemNameBuffer] : QString::fromWCharArray(lpFileSystemNameBuffer);获取卷上剩余空间/卷大小等信息
getDiskFreeSpaceExA 函数 检索有关磁盘卷上可用空间量的信息即空间总量、可用空间总量以及与调用线程关联的用户可用空间总量。 参数 驱动器根路径比如“D:”
LPCSTR pszDrive;
DWORD64 qwFreeBytesToCaller, qwTotalBytes, qwFreeBytes;
DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters;
BOOL bResult;//使用GetDiskFreeSpaceEx获取磁盘信息并打印结果bResult GetDiskFreeSpaceExA (pszDrive,(PULARGE_INTEGER)qwFreeBytesToCaller,(PULARGE_INTEGER)qwTotalBytes,(PULARGE_INTEGER)qwFreeBytes);if(bResult){printf(使用GetDiskFreeSpaceEx获取磁盘空间信息\n);printf(可获得的空闲空间字节: \t%I64d\n, qwFreeBytesToCaller);printf(空闲空间字节: \t%I64d\n, qwFreeBytes);printf(磁盘总容量字节: \t%I64d\n, qwTotalBytes);}//使用GetDiskFreeSpace获取磁盘信息并打印结果
bResult GetDiskFreeSpaceA (pszDrive,dwSectPerClust,dwBytesPerSect,dwFreeClusters,dwTotalClusters);if(bResult)
{printf(\n使用GetDiskFreeSpace获取磁盘空间信息\n);printf(空闲的簇数量 : \t%d\n,dwFreeClusters);printf(总簇数量 : \t%d\n,dwTotalClusters);printf(每簇的扇区数量 : \t%d\n,dwSectPerClust);printf(每扇区的容量字节: \t%d\n,dwBytesPerSect);printf(空闲空间字节: \t%I64d\n,(DWORD64)dwFreeClusters*(DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect);printf(磁盘总容量字节: \t%I64d\n,(DWORD64)dwTotalClusters*(DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect);
}
格式化卷
IVdsVolumeMF3::FormatEx2 方法 格式化分区上的文件系统卷。 此方法与 IVdsVolumeMF2::FormatEx 方法相同只是使用 Options 参数指定格式设置选项。
IVdsVolumeMF3接口通过 IVdsVolume接口实例获取 IVdsVolumeMF3 * pVolumeMF3NULL;//判断 IVdsVolume 接口实例是否有效//IFNULL_GOTO(pVolume,pVolume No instantiation!,out);HRESULT hResult pVolume-QueryInterface(IID_IVdsVolumeMF3,(void **)pVolumeMF3);if (hResult ! S_OK){qDebug(Could not initialize_pVolumeMF3 : %s, GetLastError());pVolumeMF3NULL;}FormatEx2 格式化分区
// The following should match VDS_FSOF_FLAGS as much as possible
#define FP_FORCE 0x00000001
#define FP_QUICK 0x00000002LPWSTR _pwszFileSystemTypeName(LPWSTR)LNTFS;
USHORT _usFileSystemRevisionNULL;
ULONG _ulDesiredUnitAllocationSizeNULL;
LPWSTR _pwszLabel(LPWSTR)L数据分区
DWORD _OptionsFP_FORCE|FP_QUICKbool resultfalse;
//判断pVolumeMF3实例是否有效
//IFNULL_INIT_ISNULL_GOTO(pVolumeMF3,initialize_pVolumeMF3(),IVdsAdvancedDisk No instantiation! ,out);
IVdsAsync* pAsyncNULL;
ULONG ulPercentCompleted0;
HRESULT hResult pVolumeMF3-FormatEx2( _pwszFileSystemTypeName, _usFileSystemRevision, _ulDesiredUnitAllocationSize,_pwszLabel, _Options,pAsync);
ULONG jindu0;
while (SUCCEEDED(hResult)) {if (IS_ERROR(hResult)) {pAsync-Cancel();break;}HRESULT hresult2;hResult pAsync-QueryStatus( hresult2, ulPercentCompleted);if (SUCCEEDED(hResult)) {hResulthresult2;if (hResult S_OK)break;if (hResult VDS_E_OPERATION_PENDING)hResult S_OK;}if(jindu!ulPercentCompleted){jinduulPercentCompleted;qDebug() schedule : jindu;}if(ulPercentCompleted100)break;
}
result(hResultS_OK);
if(!result)qDebug()pVolumeMF3 FormatEx2 is failed! WindowsError::GetVdsError(hResult);需要注意的是在格式化分区后都需要根据分区偏移量获取对应的卷在指定文件格式类型格式化卷。否则创建的卷将不可用无法识别!
测试时注意保存重要数据!在修改操作卷时需要注意操作流程 更改卷文件系统: 打开卷。 锁定卷。 设置卷的格式。 卸载卷。 解锁卷。 关闭卷柄。