提示

在对磁盘和卷进行处理时,建议简单了解他们之间的关系,可以参考
【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 : \\?\PhysicalDrive2
  HANDLE 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(hDrive==INVALID_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 size=0;
 if(!DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
                     NULL, 0, geometry, sizeof(geometry), &size, NULL)||size==0)
 {
     CloseHandle(hDrive);
     continue;
 }
 //qDebug()<<"柱面数量: "<<QString::number(DiskGeometry->Geometry.Cylinders.QuadPart,10);

格式分区

使用IVdsAdvancedDisk::FormatPartition方法格式化创建好的分区,此方法仅设置 OEM、ESP 和未知分区的格式,如果是其他分区需要根据磁盘分区偏移量,找到对应的卷然后使用 IVdsVolumeMF::FormatIVdsVolumeMF2::FormatEx 方法格式化相应的卷。这样磁盘分区才能正常使用,计算机管理-》磁盘管理才会正常显示分区

/*
//!.h
        VDS 实现此方法。
        此方法仅设置 OEM、ESP 和未知分区的格式。
         对于其他分区,必须使用 IVdsVolumeMF::Format 或 IVdsVolumeMF2::FormatEx 方法格式化相应的卷。
        请注意,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 _bForce=true,
                            BOOL _bQuickFormat=true,
                            BOOL _bEnableCompression=false);


//!.Cpp
bool D_FormatPartition( ULONGLONG _ullOffset,
                                        VDS_FILE_SYSTEM_TYPE _type,
                                        LPWSTR _pwszLabel,
                                        DWORD _dwUnitAllocationSize,
                                        BOOL _bForce,
                                        BOOL _bQuickFormat,
                                        BOOL _bEnableCompression)
{

    bool result=false;
    //pAdvancedDisk 是 IVdsAdvancedDisk 接口的具体实例
    
    IVdsAsync* pAsync=NULL;
    ULONG ulPercentCompleted=0;
    HRESULT hResult =pAdvancedDisk->FormatPartition( _ullOffset, _type, _pwszLabel, _dwUnitAllocationSize,_bForce,_bQuickFormat, _bEnableCompression,&pAsync);
    ULONG jindu=0;
    while (SUCCEEDED(hResult)) {
        if (IS_ERROR(hResult)) {
            pAsync->Cancel();
            break;
        }
        HRESULT hresult2;
        hResult = pAsync->QueryStatus( &hresult2, &ulPercentCompleted);
        if (SUCCEEDED(hResult)) {
            hResult=hresult2;
            if (hResult == S_OK)
                break;
            if (hResult == VDS_E_OPERATION_PENDING)
                hResult = S_OK;
        }

        if(jindu!=ulPercentCompleted)
        {
            jindu=ulPercentCompleted;
            qDebug()<<" schedule : "<<jindu;
        }
        if(ulPercentCompleted==100)
            break;
    }
    result=(hResult==S_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 ullSize=1215277056;
  ///设置后方分区大小
  LONGLONG ullSize=2373588*prop.ulBytesPerSector;
  LONGLONG ullOffset=DiskUllSize-ullSize;

  CREATE_DISK CreateDisk = {PARTITION_STYLE_MBR, {{0}}};
  CreateDisk.PartitionStyle=PARTITION_STYLE_MBR;
  CreateDisk.Mbr.Signature=(DWORD)GetTickCount64();

  DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = {0};
  DriveLayoutEx.PartitionStyle=PARTITION_STYLE_MBR;
  DriveLayoutEx.PartitionCount=2;
  DriveLayoutEx.PartitionEntry[0].PartitionStyle=PARTITION_STYLE_MBR;
  DriveLayoutEx.PartitionEntry[0].StartingOffset.QuadPart=ullOffset;
  DriveLayoutEx.PartitionEntry[0].PartitionLength.QuadPart=ullSize;
  DriveLayoutEx.PartitionEntry[0].PartitionNumber=1;
  DriveLayoutEx.PartitionEntry[0].RewritePartition=TRUE;
  DriveLayoutEx.PartitionEntry[0].Mbr.BootIndicator=TRUE;
  DriveLayoutEx.PartitionEntry[0].Mbr.PartitionType=0xef;
  DriveLayoutEx.PartitionEntry[0].Mbr.RecognizedPartition=TRUE;
  //设置中间间隔
  LONGLONG Offset=(2048*prop.ulBytesPerSector);
  //设置分区大小
  LONGLONG OffullSize=DiskUllSize-ullSize-Offset;
  DriveLayoutEx.PartitionEntry[1].PartitionStyle=PARTITION_STYLE_MBR;
  DriveLayoutEx.PartitionEntry[1].StartingOffset.QuadPart=Offset;
  DriveLayoutEx.PartitionEntry[1].PartitionLength.QuadPart=OffullSize;
  DriveLayoutEx.PartitionEntry[1].PartitionNumber=2;
  DriveLayoutEx.PartitionEntry[1].RewritePartition=TRUE;
  DriveLayoutEx.PartitionEntry[1].Mbr.BootIndicator=TRUE;
  DriveLayoutEx.PartitionEntry[1].Mbr.PartitionType=0xef;
  DriveLayoutEx.PartitionEntry[1].Mbr.RecognizedPartition=TRUE;
  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();
    size=sizeof(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*  pCreatePartition=NULL;
    //判断 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());
        pCreatePartition=NULL;
    }

  • 创建分区:
///  如果起始分区不在第一柱形内,分区后的分区偏移量会发生偏适用于创建一个分区差
    /// \brief 在基本磁盘上创建分区。  [此方法取代 IVdsAdvancedDisk::CreatePartition 方法。]
    ///  *当调用方同时指定 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 result=false;
 //判断IVdsCreatePartitionEx 接口是否有效 
 //IFNULL_INIT_ISNULL_GOTO(pCreatePartition,initialize_pCreatePartition(),"pCreatePartition No instantiation! ",out);
  IVdsAsync* pAsync=NULL;
   ULONG ulPercentCompleted;
   HRESULT hResult =pCreatePartition->CreatePartitionEx(_ullOffset,_ullSize,_ulAlign,para,&pAsync);
   ULONG jindu=0;
   while (SUCCEEDED(hResult)) {
       if (IS_ERROR(hResult)) {
           pAsync->Cancel();
           break;
       }
       HRESULT hresult2;
       hResult = pAsync->QueryStatus( &hresult2, &ulPercentCompleted);
       if (SUCCEEDED(hResult)) {
           hResult=hresult2;
           if (hResult == S_OK)
               break;
           if (hResult == VDS_E_OPERATION_PENDING)
               hResult = S_OK;
       }

       if(jindu!=ulPercentCompleted)
       {
           jindu=ulPercentCompleted;
           qDebug()<<" schedule : "<<jindu;
       }
       if(ulPercentCompleted==100)
           break;
   }
   result=(hResult==S_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 i=0; 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_d=QString::fromWCharArray((LPCWSTR)volume_name);
        qDebug()<<"[volume_d] "<<volume_d;
}

打开使用 CreateFile 函数创建卷对象的句柄

通过 volume_name 打开卷对象句柄
[volume_d] "\\\\?\\Volume{2efb2ac5-6828-4320-8848-041647908928}\\"

  QString volume_d=QString::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 = 8
  DISK_EXTENT Extents[8];
} VOLUME_DISK_EXTENTS_OverDide;
 VOLUME_DISK_EXTENTS_OverDide DiskExtents;
 DWORD size=0;
 //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   nVolumeNameSize=MAX_PATH+1;
   LPWSTR  lpVolumeNameBuffer=(LPWSTR)new BYTE [nVolumeNameSize * sizeof(WCHAR)];
   LPDWORD lpVolumeSerialNumber=0;
   LPDWORD lpMaximumComponentLength=0;
   LPDWORD lpFileSystemFlags=0;
   DWORD   nFileSystemNameSize=MAX_PATH+1;
   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 * pVolumeMF3=NULL;
    //判断 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());
        pVolumeMF3=NULL;
    }
  • FormatEx2 格式化分区:
// The following should match VDS_FSOF_FLAGS as much as possible
#define FP_FORCE                            0x00000001
#define FP_QUICK                            0x00000002

LPWSTR _pwszFileSystemTypeName=(LPWSTR)L"NTFS";
USHORT _usFileSystemRevision=NULL;
ULONG _ulDesiredUnitAllocationSize=NULL;
LPWSTR _pwszLabel=(LPWSTR)L"数据分区"
DWORD _Options=FP_FORCE|FP_QUICK

bool result=false;
//判断pVolumeMF3实例是否有效
//IFNULL_INIT_ISNULL_GOTO(pVolumeMF3,initialize_pVolumeMF3(),"IVdsAdvancedDisk No instantiation! ",out);
IVdsAsync* pAsync=NULL;
ULONG ulPercentCompleted=0;
HRESULT hResult =pVolumeMF3->FormatEx2( _pwszFileSystemTypeName, _usFileSystemRevision, _ulDesiredUnitAllocationSize,_pwszLabel, _Options,&pAsync);
ULONG jindu=0;
while (SUCCEEDED(hResult)) {
    if (IS_ERROR(hResult)) {
        pAsync->Cancel();
        break;
    }
    HRESULT hresult2;
    hResult = pAsync->QueryStatus( &hresult2, &ulPercentCompleted);
    if (SUCCEEDED(hResult)) {
        hResult=hresult2;
        if (hResult == S_OK)
            break;
        if (hResult == VDS_E_OPERATION_PENDING)
            hResult = S_OK;
    }

    if(jindu!=ulPercentCompleted)
    {
        jindu=ulPercentCompleted;
        qDebug()<<" schedule : "<<jindu;
    }
    if(ulPercentCompleted==100)
        break;
}
result=(hResult==S_OK);
if(!result)
    qDebug()<<"pVolumeMF3 FormatEx2 is failed! "<<WindowsError::GetVdsError(hResult);

需要注意的是,在格式化分区后都需要根据分区偏移量获取对应的卷,在指定文件格式类型格式化卷。否则创建的卷将不可用,无法识别!

  • 在修改操作卷时需要注意操作流程:
    更改卷文件系统:
    打开卷。
    锁定卷。
    设置卷的格式。
    卸载卷。
    解锁卷。
    关闭卷柄。
01-30 17:31