2016-09-19 6 views
0

Je suis coincé en train de tenter de repartitionner et de formater un lecteur flash USB en C++, toute aide serait super!Erreur lors du partitionnement et du formatage Clé USB en C++

L'objectif est de repartitionner n'importe quel lecteur flash arbitraire avec une seule partition prenant tout l'espace et formaté FAT32 (options ultérieures NTFS et EXFAT). Cela se fera en batch, avec plus de 50 appareils en même temps, avec un peu de chance, donc l'accès aux lettres n'est pas une option. Je suis capable de créer une partition, mais lorsque j'essaie IOCTL_DISK_SET_PARTITION_INFO_EX pour définir le type de format, il échoue avec 0x32, ERROR_NOT_SUPPORTED. Mais on ne sait pas exactement ce qui n'est pas supporté. Je peux partitionner manuellement le périphérique en utilisant des utilitaires tels que diskpart, donc je sais que les types de partition et de système de fichiers sont pris en charge par le périphérique. Quelqu'un peut-il aider? Mon code source complet est ci-dessous, il échoue sur l'appel DeviceIoControl() avec IOCTL_DISK_SET_PARTITION_INFO_EX.

#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

Avez-vous essayé d'exécuter votre programme en tant qu'administrateur (via "Exécuter en tant qu'administrateur")? – 1201ProgramAlarm

+0

Quel est l'objectif de 'IOCTL_DISK_SET_PARTITION_INFO_EX'? Vous avez déjà défini le type de partition dans le fichier 'IOCTL_DISK_SET_DRIVE_LAYOUT_EX' ci-dessus. –

+0

Merci pour la suggestion. Oui, j'ai essayé le clic droit et "exécuter en tant qu'administrateur" et le résultat est le même, erreur 0x32 ERROR_NOT_SUPPORTED. – Matt

Répondre

1

J'ai une solution, mais c'est un peu compliqué. J'utilise DeviceIoControl() comme ci-dessus pour partitionner le disque. Ensuite, j'utilise VDS et l'interface IID_IVdsVolumeMF pour créer le système de fichiers, mais y arriver, c'est un peu de travail. L'objectif est de partitionner et de formater tous les lecteurs flash (clés USB) sur le système. VDS va effectuer le format via l'interface IID_IVdsVolumeMF, mais il ne vous dira pas (du moins je n'ai pas compris comment) quels périphériques sont amovibles. Mais WMI vous dira quels périphériques sont amovibles, mais n'a pas de fonction de formatage. Alors ...

Première utilisation WMI pour obtenir une liste de tous les amovibles chemins de volume sur le système, par exemple:

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) 

vous présente les chemins tels que:

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

Ensuite, utilisez VDS pour obtenir une liste de tous les volumes VDS sur la machine. Fondamentalement, vous chargez VDS, puis obtenez tous les fournisseurs de logiciels. Cette source est des pièces manquantes par souci de brièveté, mais je pense que je assez pour expliquer ce qui se passe:

pSvc->QueryProviders(VDS_QUERY_SOFTWARE_PROVIDERS, &pEnumProviders) 

maintenant itérer la liste des fournisseurs obtenir les packs de chaque fournisseur:

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

maintenant itérer les paquets et obtenir tous les volumes dans chaque paquet:

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

maintenant vous avez une liste des chemins vers des périphériques amovibles, et vous avez une liste de tous les volumes sur le système. Il est temps de les comparer et de déterminer lesquels volumes sont amovible.

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! } 

utiliser maintenant cet objet de volume SDV pour formater le volume:

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 
} 

Et presto votre clé USB est formaté! Ouf .. mais ça semble marcher.

Microsoft n'a-t-il pas vraiment facilité la tâche?