2016-09-19 114 views
0

我卡住嘗試重新分區和使用C++格式化USB閃存驅動器,任何幫助將是偉大的!錯誤分區和格式化USB閃存驅動器在C + +

目標是用佔用整個空間和格式化FAT32(稍後的選項NTFS和EXFAT)的單個分區重新分區任意的閃存驅動器。這將分批完成,希望一次有50多個設備,因此不能選擇驅動器號訪問。我能夠創建一個分區,但是當我嘗試IOCTL_DISK_SET_PARTITION_INFO_EX來設置格式類型時,它將以0x32,ERROR_NOT_SUPPORTED失敗。但目前尚不清楚究竟哪些不支持。我可以使用實用程序(如diskpart)手動對設備進行分區,因此我知道設備支持分區和文件系統類型。誰能幫忙?我的完整源代碼如下,在使用IOCTL_DISK_SET_PARTITION_INFO_EX調用DeviceIoControl()時失敗。

#include "stdafx.h" 
#include <random> 
#include <Windows.h> 
#include <atlstr.h> 
#include <iostream> 
#include <assert.h> 


using namespace std; 

#define THROW_CSTRING(a, b) { CString csE; csE.Format(a, b); throw csE; } 
#define RANDOM_DWORD {DWORD(rand()) | DWORD(rand() << 8) | DWORD(rand() << 16) | DWORD(rand() << 24)} 


int main() 
{ 
    DRIVE_LAYOUT_INFORMATION_EX* pdg = NULL; 
    HANDLE hDevice = INVALID_HANDLE_VALUE; 

    try 
    { 

    hDevice = CreateFile(L"\\\\.\\PhysicalDrive2", 
          GENERIC_READ | GENERIC_WRITE, 
          0,    // Only we can access 
          NULL,   // Default security 
          OPEN_EXISTING, // For hardware, open existing 
          0,    // File attributes 
          NULL);   //Do not copy attributes 
    if (hDevice == INVALID_HANDLE_VALUE) 
    { 
     THROW_CSTRING(L"ERROR: CreateFile() failed: 0x%x", GetLastError()); 
    } 

    CREATE_DISK dsk; 
    memset(&dsk, 0, sizeof(dsk)); 
    CREATE_DISK_MBR dskmbr = { 0 }; 
    dskmbr.Signature = 1; 
    dsk.PartitionStyle = PARTITION_STYLE_MBR; 
    dsk.Mbr = dskmbr; 

    // DRIVE_LAYOUT_INFORMAITON_EX has an array of partition info at the end, need enough for 4 partitions minimum 
    int iDriveLayoutBytesRequired = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX) * 3; 
    pdg = (DRIVE_LAYOUT_INFORMATION_EX*)new BYTE[iDriveLayoutBytesRequired]; 
    memset(pdg, 0, iDriveLayoutBytesRequired); 

    DRIVE_LAYOUT_INFORMATION_MBR mbrlayout = { 0 }; 
    mbrlayout.Signature = RANDOM_DWORD; 
    pdg->PartitionStyle = PARTITION_STYLE_MBR; 
    pdg->Mbr = mbrlayout; 
    pdg->PartitionCount = 1; 

    DWORD dwBytesReturned = 0; 


    if (!DeviceIoControl(hDevice, IOCTL_DISK_CREATE_DISK, &dsk, sizeof(dsk), NULL, 0, &dwBytesReturned, NULL)) 
    { 
     THROW_CSTRING(L"ERROR: IOCTL_DISK_CREATE_DISK failed: 0x%x", GetLastError()); 
    } 


    // Get the drive dimensions, then use that info to create a new partition 

    // Drive length 
    GET_LENGTH_INFORMATION sLenInfo = { 0 }; 
    if (!DeviceIoControl(hDevice, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &sLenInfo, sizeof(sLenInfo), &dwBytesReturned, NULL)) 
    { 
     THROW_CSTRING(L"ERROR: IOCTL_DISK_GET_LENGTH_INFO failed: 0x%x", GetLastError()); 
    } 
    assert(sizeof(sLenInfo.Length.QuadPart) == sizeof(__int64)); 
    __int64 iDiskLengthBytes = sLenInfo.Length.QuadPart; 


    pdg->PartitionStyle = PARTITION_STYLE_MBR; 
    pdg->PartitionCount = 4; 
    pdg->Mbr.Signature = 1; 

    pdg->PartitionEntry[0].PartitionStyle = PARTITION_STYLE_MBR; 
    pdg->PartitionEntry[0].StartingOffset.QuadPart = 0; 
    pdg->PartitionEntry[0].PartitionLength.QuadPart = iDiskLengthBytes; 
    pdg->PartitionEntry[0].PartitionNumber = 1; 
    pdg->PartitionEntry[0].RewritePartition = TRUE; 

    //pdg->PartitionEntry[0].Mbr.PartitionType = PARTITION_IFS; // NTFS 
    pdg->PartitionEntry[0].Mbr.PartitionType = PARTITION_FAT32; 
    pdg->PartitionEntry[0].Mbr.BootIndicator = TRUE; 
    pdg->PartitionEntry[0].Mbr.RecognizedPartition = 1; 
    pdg->PartitionEntry[0].Mbr.HiddenSectors = 0; 


    // Partition device 
    if (!DeviceIoControl(hDevice, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, pdg, iDriveLayoutBytesRequired, NULL, 0, &dwBytesReturned, NULL)) 
    { 
     THROW_CSTRING(L"ERROR: IOCTL_DISK_SEt_DRIVE_LAYOUT_EX failed: 0x%x", GetLastError()); 
    } 

    // Tell the driver to flush its cache 
    if (!DeviceIoControl(hDevice, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) 
    { 
     THROW_CSTRING(L"ERROR: IOCTL_DISK_UPDATE_PROPERTIES failed: 0x%x", GetLastError()); 
    } 

    SET_PARTITION_INFORMATION_EX dskinfo; 
    memset(&dskinfo, 0, sizeof(dskinfo)); 
    dskinfo.PartitionStyle = PARTITION_STYLE_MBR; 
    dskinfo.Mbr.PartitionType = PARTITION_FAT32; 

    if (!DeviceIoControl(hDevice, IOCTL_DISK_SET_PARTITION_INFO_EX, &dskinfo, sizeof(dskinfo), NULL, 0, &dwBytesReturned, NULL)) 
    { 
     THROW_CSTRING(L"ERROR: IOCTL_DISK_SET_PARTITION_INFO_EX failed: 0x%x", GetLastError()); 
    } 

    } 

    catch (CString csErr) 
    { 
    // Error lookup: https://msdn.microsoft.com/en-us/library/w indows/desktop/ms681382(v=vs.85).aspx 
    // 0x7a - ERROR_INSUFFICIENT_BUFFER 
    // 0x57 - ERROR_INVALID_PARAMETER 
    // 0x32 - ERROR_NOT_SUPPORTED 
    // 0x18 - ERROR_BAD_LENGTH 
    // 0x05 - ERROR_ACCESS_DENIED 
    wcout << csErr.GetString(); 
    } 

    CloseHandle(hDevice); 
    delete pdg; 
    return 0; 
} 
+0

您是否曾嘗試以管理員身份運行程序(通過「以管理員身份運行」)? – 1201ProgramAlarm

+0

「IOCTL_DISK_SET_PARTITION_INFO_EX」的用途是什麼?您已經在上面的'IOCTL_DISK_SET_DRIVE_LAYOUT_EX'中設置了分區類型。 –

+0

感謝您的建議。是的,我嘗試右鍵單擊並「以管理員身份運行」,結果是相同的,錯誤0x32 ERROR_NOT_SUPPORTED。 – Matt

回答

1

我有一個解決方案,但它有點複雜。我使用上面的DeviceIoControl()來分區磁盤。然後,我使用VDS和IID_IVdsVolumeMF界面來創建文件系統,但是到那裏工作有點麻煩。目標是對系統上的所有閃存驅動器(USB記憶棒)進行分區和格式化。 VDS將通過IID_IVdsVolumeMF接口執行格式,但它不會告訴您(至少我沒有弄清楚)哪些設備是可移除的。但是WMI會告訴你哪些設備是可移動的,但沒有格式化功能。所以......

首先使用WMI來獲取系統中所有移動量路徑列表,例如:

CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc) 
pLoc->ConnectServer(CComBSTR(L"ROOT\\CIMV2"), nullptr, nullptr, nullptr, 0, nullptr, nullptr, pWbemSvc) 
CoSetProxyBlanket(
             *pWbemSvc,      // Indicates the proxy to set 
             RPC_C_AUTHN_WINNT,   // RPC_C_AUTHN_xxx 
             RPC_C_AUTHZ_NONE,   // RPC_C_AUTHZ_xxx 
             NULL,      // Server principal name 
             RPC_C_AUTHN_LEVEL_CALL,  // RPC_C_AUTHN_LEVEL_xxx 
             RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx 
             NULL,      // client identity 
             EOAC_NONE     // proxy capabilities 

pWbemSvc->ExecQuery(CComBSTR(L"WQL"), CComBSTR(L"SELECT * FROM Win32_Volume WHERE DriveType=2"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator) 

爲您提供了諸如路徑:

L"\\\\?\\Volume{3899cb7b-7c3f-11e6-bf82-005056c00008}\\" 

然後使用VDS獲取機器上所有VDS卷的列表。基本上你加載VDS,然後得到所有的軟件提供商。這個來源是失蹤了簡短的部分,但我想我留下了足夠的解釋發生了什麼:

pEnumProviders->Next(1, &pUnk, &cFetched) 
pProv = pUnk; 
pProv->QueryPacks(&pEnumpacks) 
vPacks.push_back(pEnumpacks); 

現在遍歷:

pSvc->QueryProviders(VDS_QUERY_SOFTWARE_PROVIDERS, &pEnumProviders) 

通過供應商正從各個供應商的包列表現在迭代禮包並獲得所有在每個包的卷:

iterator iPacks = vPacks.begin(); 
(*iPacks)->Next(1, &pUnk, &cFetched) 
pPack = pUnk; 
pPack->QueryVolumes(&pEnumvolumes) 
pvpEnumvolumes->push_back(pEnumvolumes) 

現在你有路徑可移動設備的列表,你必須在系統上所有卷的列表。時間來比較它們,並找出哪些可移動

iVolEnum = pvpEnumOfVDSVolumes->begin() 
(*iVolEnum)->Next(1, &pUnk, &cFetched) 
pVMF3 = pUnk; 
CComHeapPtr<LPWSTR> pVDSVolumePaths; 
pVMF3->QueryVolumeGuidPathnames(&pVDSVolumePaths, &nPaths) 
iterator iWMIVolPath = pvWMIRemovableVols->begin(); 
loop.. 
if (wcscmp(iWMIVolPath->data(), pVDSVolumePaths[i]) == 0) 
{ // VDS Vol is removable! } 

現在使用VDS卷對象格式化卷:

foreach(vol in vRemovableVDSVols) 
{ 
CComQIPtr<IVdsVolume> pVolume = *(vol); 
IVdsVolumeMF *pVolumeMF; 
pVolume->QueryInterface(IID_IVdsVolumeMF, (void **)&pVolumeMF); 
pVolumeMF->Format( VDS_FST_FAT32, 
           L"MyFob", 
           512, // alloc size 
           true, // force 
           false, // quick 
           false, // compression 
           &pAsync); // async 
} 

而急的U盤格式化!呃..但它似乎在工作。

微軟真的沒有讓這個更容易嗎?