2016-03-04 2 views
3

Iam essayant d'utiliser DeviceIOControl pour créer plusieurs partiions en USB. Il crée toujours une seule partition.Création de plusieurs partitions sur un périphérique USB en utilisant C#

Voici mon code source

[DllImport("kernel32.dll", SetLastError = true)] 
     static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, 
      uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, 
      uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

     [DllImport("kernel32")] 
     static extern int CloseHandle(IntPtr handle); 


     [DllImport("kernel32")] 
     private static extern int DeviceIoControl 
      (IntPtr deviceHandle, uint ioControlCode, 
      IntPtr inBuffer, int inBufferSize, 
      IntPtr outBuffer, int outBufferSize, 
      ref int bytesReturned, IntPtr overlapped); 

    public const uint GENERIC_READ = 0x80000000; 
     public const uint GENERIC_WRITE = 0x40000000; 
     public const uint FILE_SHARE_READ = 0x00000001; 
     public const uint FILE_SHARE_WRITE = 0x00000002; 
     public const uint OPEN_EXISTING = 0x00000003; 
     public const uint FILE_ATTRIBUTE_NORMAL = 0x80; 
     public const uint FSCTL_ALLOW_EXTENDED_DASD_IO = 0x90083; 
     public const int DRIVE_ACCESS_RETRIES = 10; 
     public const int DRIVE_ACCESS_TIMEOUT = 15000; 
     public const uint FSCTL_LOCK_VOLUME = 0x00090018; 
     static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); 
     public const uint IOCTL_DISK_GET_DRIVE_LAYOUT_EX = 0x00070050; 
     public const uint IOCTL_DISK_GET_DRIVE_GEOMETRY_EX = 0x000700A0; 
     public const uint IOCTL_DISK_CREATE_DISK = 0x0007C058; 
     public const uint IOCTL_DISK_UPDATE_PROPERTIES = 0x00070140; 
     public const uint IOCTL_DISK_SET_DRIVE_LAYOUT_EX = 0x0007C054; 
     public const int MIN_EXTRA_PART_SIZE = 1024 * 1024; 
     public static int mediaType = 0; 


/// <summary> 
     /// Describes the geometry of disk devices and media. 
     /// </summary> 
     [StructLayout(LayoutKind.Explicit)] 
     public struct DISK_GEOMETRY 
     { 
      /// <summary> 
      /// The number of cylinders. 
      /// </summary> 
      [FieldOffset(0)] 
      public Int64 Cylinders; 

      /// <summary> 
      /// The type of media. For a list of values, see MEDIA_TYPE. 
      /// </summary> 
      [FieldOffset(8)] 
      public MEDIA_TYPE MediaType; 

      /// <summary> 
      /// The number of tracks per cylinder. 
      /// </summary> 
      [FieldOffset(12)] 
      public uint TracksPerCylinder; 

      /// <summary> 
      /// The number of sectors per track. 
      /// </summary> 
      [FieldOffset(16)] 
      public uint SectorsPerTrack; 

      /// <summary> 
      /// The number of bytes per sector. 
      /// </summary> 
      [FieldOffset(20)] 
      public uint BytesPerSector; 
     } 



     /// <summary> 
     /// Describes the extended geometry of disk devices and media. 
     /// </summary> 
     [StructLayout(LayoutKind.Explicit)] 
     private struct DISK_GEOMETRY_EX 
     { 
      /// <summary> 
      /// A DISK_GEOMETRY structure. 
      /// </summary> 
      [FieldOffset(0)] 
      public DISK_GEOMETRY Geometry; 

      /// <summary> 
      /// The disk size, in bytes. 
      /// </summary> 
      [FieldOffset(24)] 
      public Int64 DiskSize; 

      /// <summary> 
      /// Any additional data. 
      /// </summary> 
      [FieldOffset(32)] 
      public Byte Data; 
     } 



     /// <summary> 
     /// Represents the format of a partition. 
     /// </summary> 
     public enum PARTITION_STYLE : uint 
     { 
      /// <summary> 
      /// Master boot record (MBR) format. 
      /// </summary> 
      PARTITION_STYLE_MBR = 0, 

      /// <summary> 
      /// GUID Partition Table (GPT) format. 
      /// </summary> 
      PARTITION_STYLE_GPT = 1, 

      /// <summary> 
      /// Partition not formatted in either of the recognized formats—MBR or GPT. 
      /// </summary> 
      PARTITION_STYLE_RAW = 2 
     } 

     /// <summary> 
     /// Contains partition information specific to master boot record (MBR) disks. 
     /// </summary> 
     [StructLayout(LayoutKind.Explicit)] 
     public struct PARTITION_INFORMATION_MBR 
     { 
      #region Constants 
      /// <summary> 
      /// An unused entry partition. 
      /// </summary> 
      public const byte PARTITION_ENTRY_UNUSED = 0x00; 

      /// <summary> 
      /// A FAT12 file system partition. 
      /// </summary> 
      public const byte PARTITION_FAT_12 = 0x01; 

      /// <summary> 
      /// A FAT16 file system partition. 
      /// </summary> 
      public const byte PARTITION_FAT_16 = 0x04; 

      /// <summary> 
      /// An extended partition. 
      /// </summary> 
      public const byte PARTITION_EXTENDED = 0x05; 

      /// <summary> 
      /// An IFS partition. 
      /// </summary> 
      public const byte PARTITION_IFS = 0x07; 

      /// <summary> 
      /// A FAT32 file system partition. 
      /// </summary> 
      public const byte PARTITION_FAT32 = 0x0B; 

      /// <summary> 
      /// A logical disk manager (LDM) partition. 
      /// </summary> 
      public const byte PARTITION_LDM = 0x42; 

      /// <summary> 
      /// An NTFT partition. 
      /// </summary> 
      public const byte PARTITION_NTFT = 0x80; 

      /// <summary> 
      /// A valid NTFT partition. 
      /// 
      /// The high bit of a partition type code indicates that a partition is part of an NTFT mirror or striped array. 
      /// </summary> 
      public const byte PARTITION_VALID_NTFT = 0xC0; 
      #endregion 

      /// <summary> 
      /// The type of partition. For a list of values, see Disk Partition Types. 
      /// </summary> 
      [FieldOffset(0)] 
      [MarshalAs(UnmanagedType.U1)] 
      public byte PartitionType; 

      /// <summary> 
      /// If this member is TRUE, the partition is bootable. 
      /// </summary> 
      [FieldOffset(1)] 
      [MarshalAs(UnmanagedType.I1)] 
      public bool BootIndicator; 

      /// <summary> 
      /// If this member is TRUE, the partition is of a recognized type. 
      /// </summary> 
      [FieldOffset(2)] 
      [MarshalAs(UnmanagedType.I1)] 
      public bool RecognizedPartition; 

      /// <summary> 
      /// The number of hidden sectors in the partition. 
      /// </summary> 
      [FieldOffset(4)] 
      public uint HiddenSectors; 
     } 

     /// <summary> 
     /// Contains GUID partition table (GPT) partition information. 
     /// </summary> 
     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] 
     public struct PARTITION_INFORMATION_GPT 
     { 
      /// <summary> 
      /// A GUID that identifies the partition type. 
      /// 
      /// Each partition type that the EFI specification supports is identified by its own GUID, which is 
      /// published by the developer of the partition. 
      /// </summary> 
      [FieldOffset(0)] 
      public Guid PartitionType; 

      /// <summary> 
      /// The GUID of the partition. 
      /// </summary> 
      [FieldOffset(16)] 
      public Guid PartitionId; 

      /// <summary> 
      /// The Extensible Firmware Interface (EFI) attributes of the partition. 
      /// 
      /// </summary> 
      [FieldOffset(32)] 
      public UInt64 Attributes; 

      /// <summary> 
      /// A wide-character string that describes the partition. 
      /// </summary> 
      [FieldOffset(40)] 
      public string Name; 
     } 
     /// <summary> 
     /// Provides information about a drive's master boot record (MBR) partitions. 
     /// </summary> 
     [StructLayout(LayoutKind.Explicit)] 
     private struct DRIVE_LAYOUT_INFORMATION_MBR 
     { 
      /// <summary> 
      /// The signature of the drive. 
      /// </summary> 
      [FieldOffset(0)] 
      public uint Signature; 
     } 

     /// <summary> 
     /// Contains information about a drive's GUID partition table (GPT) partitions. 
     /// </summary> 
     [StructLayout(LayoutKind.Explicit)] 
     private struct DRIVE_LAYOUT_INFORMATION_GPT 
     { 
      /// <summary> 
      /// The GUID of the disk. 
      /// </summary> 
      [FieldOffset(0)] 
      public Guid DiskId; 

      /// <summary> 
      /// The starting byte offset of the first usable block. 
      /// </summary> 
      [FieldOffset(16)] 
      public Int64 StartingUsableOffset; 

      /// <summary> 
      /// The size of the usable blocks on the disk, in bytes. 
      /// </summary> 
      [FieldOffset(24)] 
      public Int64 UsableLength; 

      /// <summary> 
      /// The maximum number of partitions that can be defined in the usable block. 
      /// </summary> 
      [FieldOffset(32)] 
      public uint MaxPartitionCount; 
     } 


     /// <summary> 
     /// Contains information about a disk partition. 
     /// </summary> 
     [StructLayout(LayoutKind.Explicit)] 
     public struct PARTITION_INFORMATION_EX 
     { 
      /// <summary> 
      /// The format of the partition. For a list of values, see PARTITION_STYLE. 
      /// </summary> 
      [FieldOffset(0)] 
      public PARTITION_STYLE PartitionStyle; 

      /// <summary> 
      /// The starting offset of the partition. 
      /// </summary> 
      [FieldOffset(8)] 
      public Int64 StartingOffset; 

      /// <summary> 
      /// The length of the partition, in bytes. 
      /// </summary> 
      [FieldOffset(16)] 
      public Int64 PartitionLength; 

      /// <summary> 
      /// The number of the partition (1-based). 
      /// </summary> 
      [FieldOffset(24)] 
      public uint PartitionNumber; 

      /// <summary> 
      /// If this member is TRUE, the partition information has changed. When you change a partition (with 
      /// IOCTL_DISK_SET_DRIVE_LAYOUT), the system uses this member to determine which partitions have changed 
      /// and need their information rewritten. 
      /// </summary> 
      [FieldOffset(28)] 
      [MarshalAs(UnmanagedType.I1)] 
      public bool RewritePartition; 

      /// <summary> 
      /// A PARTITION_INFORMATION_MBR structure that specifies partition information specific to master boot 
      /// record (MBR) disks. The MBR partition format is the standard AT-style format. 
      /// </summary> 
      [FieldOffset(32)] 
      public PARTITION_INFORMATION_MBR Mbr; 

      /// <summary> 
      /// A PARTITION_INFORMATION_GPT structure that specifies partition information specific to GUID partition 
      /// table (GPT) disks. The GPT format corresponds to the EFI partition format. 
      /// </summary> 
      [FieldOffset(32)] 
      public PARTITION_INFORMATION_GPT Gpt; 
     } 


     [StructLayout(LayoutKind.Explicit)] 
     private struct DRIVE_LAYOUT_INFORMATION_UNION 
     { 
      [FieldOffset(0)] 
      public DRIVE_LAYOUT_INFORMATION_MBR Mbr; 

      [FieldOffset(0)] 
      public DRIVE_LAYOUT_INFORMATION_GPT Gpt; 
     } 

     /// <summary> 
     /// Contains extended information about a drive's partitions. 
     /// </summary> 
     [StructLayout(LayoutKind.Explicit)] 
     private struct DRIVE_LAYOUT_INFORMATION_EX 
     { 
      /// <summary> 
      /// The style of the partitions on the drive enumerated by the PARTITION_STYLE enumeration. 
      /// </summary> 
      [FieldOffset(0)] 
      public PARTITION_STYLE PartitionStyle; 

      /// <summary> 
      /// The number of partitions on a drive. 
      /// 
      /// On disks with the MBR layout, this value is always a multiple of 4. Any partitions that are unused have 
      /// a partition type of PARTITION_ENTRY_UNUSED. 
      /// </summary> 
      [FieldOffset(4)] 
      public uint PartitionCount; 

      /// <summary> 
      /// A DRIVE_LAYOUT_INFORMATION_MBR structure containing information about the master boot record type 
      /// partitioning on the drive. 
      /// </summary> 
      [FieldOffset(8)] 
      public DRIVE_LAYOUT_INFORMATION_UNION Mbr; 

      /// <summary> 
      /// A DRIVE_LAYOUT_INFORMATION_GPT structure containing information about the GUID disk partition type 
      /// partitioning on the drive. 
      /// </summary> 
      // [FieldOffset(8)] 
      //public DRIVE_LAYOUT_INFORMATION_GPT Gpt; 

      /// <summary> 
      /// A variable-sized array of PARTITION_INFORMATION_EX structures, one structure for each partition on the 
      /// drive. 
      /// </summary> 
      [FieldOffset(48)] 
      [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 4)] 
      public PARTITION_INFORMATION_EX[] PartitionEntry; 

     } 

     [StructLayout(LayoutKind.Explicit)] 
     private struct CREATE_DISK_MBR 
     { 
      [FieldOffset(0)] 
      public uint Signature; 
     } 

     [StructLayout(LayoutKind.Explicit)] 
     private struct CREATE_DISK_GPT 
     { 
      [FieldOffset(0)] 
      public Guid DiskId; 

      [FieldOffset(16)] 
      public uint MaxPartitionCount; 
     } 

     [StructLayout(LayoutKind.Explicit)] 
     private struct CREATE_DISK 
     { 
      [FieldOffset(0)] 
      public PARTITION_STYLE PartitionStyle; 

      [FieldOffset(4)] 
      public CREATE_DISK_MBR Mbr; 

      [FieldOffset(4)] 
      public CREATE_DISK_GPT Gpt; 
     } 


static IntPtr GetHandle(int driveIndex) 
     { 
      IntPtr handle; 
      //bool locked = false; 

      Program p = new Program(); 
      string physicalName = p.GetPhysicalName(driveIndex); 

      Debug.WriteLine(physicalName); 

      handle = CreateFile(physicalName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 
         IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero); 

      if (handle == INVALID_HANDLE_VALUE) 
      { 
       Debug.WriteLine(Marshal.GetLastWin32Error()); 
       return IntPtr.Zero; 
      } 
      return handle; 
     } 

     //Returns true if drive Index is successfully created 
     //Returns false if not created successfully 
     static bool CreatePartition(int driveIndex) 
     { 
      IntPtr handle = GetHandle(driveIndex); 

      if (handle == INVALID_HANDLE_VALUE) 
      { 
       return false; 
      } 

      //Step 2: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX to get the physical disk's geometry (we need some information in it to fill partition data) 
      //The number of surfaces (or heads, which is the same thing), cylinders, and sectors vary a lot; the specification of the number of each is called the geometry of a hard disk. 
      //The geometry is usually stored in a special, battery-powered memory location called the CMOS RAM , from where the operating system can fetch it during bootup or driver initialization. 
      int size = 0; 
      DISK_GEOMETRY_EX geometry = new DISK_GEOMETRY_EX(); 
      IntPtr lpOutBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DISK_GEOMETRY_EX))); 
      Marshal.StructureToPtr(geometry, lpOutBuffer, false); 
      int result = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, IntPtr.Zero, 0, lpOutBuffer, 
              Marshal.SizeOf(typeof(DISK_GEOMETRY_EX)), 
              ref size, IntPtr.Zero); 
      geometry = (DISK_GEOMETRY_EX)Marshal.PtrToStructure(lpOutBuffer, typeof(DISK_GEOMETRY_EX)); 


      //Step 3: IOCTL_DISK_CREATE_DISK is used to initialize a disk with an empty partition table. 
      CREATE_DISK createDisk = new CREATE_DISK(); 
      createDisk.PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR; 
      createDisk.Mbr.Signature = 1; 

      IntPtr createDiskBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CREATE_DISK))); 
      Marshal.StructureToPtr(createDisk, createDiskBuffer, false); 

      byte[] arr1 = new byte[Marshal.SizeOf(typeof(CREATE_DISK))]; 
      Marshal.Copy(createDiskBuffer, arr1, 0, Marshal.SizeOf(typeof(CREATE_DISK))); 

      result = DeviceIoControl(handle, IOCTL_DISK_CREATE_DISK, createDiskBuffer, Marshal.SizeOf(typeof(CREATE_DISK)), 
             IntPtr.Zero, 0, ref size, IntPtr.Zero); 

      result = DeviceIoControl(handle, IOCTL_DISK_UPDATE_PROPERTIES, IntPtr.Zero, 0, IntPtr.Zero, 0, ref size, IntPtr.Zero); 


      //Step 4: IOCTL_DISK_SET_DRIVE_LAYOUT_EX to repartition a disk as specified. 
      //Note: use IOCTL_DISK_UPDATE_PROPERTIES to synchronize system view after IOCTL_DISK_CREATE_DISK and IOCTL_DISK_SET_DRIVE_LAYOUT_EX 
      /* DWORD driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX) * 4 * 25; 
      DRIVE_LAYOUT_INFORMATION_EX *DriveLayoutEx = (DRIVE_LAYOUT_INFORMATION_EX *) new BYTE[driveLayoutSize];*/ 



      IntPtr driveLayoutbuffer = Marshal.AllocHGlobal(624); 
      DRIVE_LAYOUT_INFORMATION_EX driveLayoutEx = new DRIVE_LAYOUT_INFORMATION_EX(); 
      int pn = 0; 
      driveLayoutEx.PartitionEntry = new PARTITION_INFORMATION_EX[4]; 


      mediaType = (int)geometry.Geometry.MediaType; 
      Int64 bytes_per_track = (geometry.Geometry.SectorsPerTrack) * (geometry.Geometry.BytesPerSector); 

      driveLayoutEx.PartitionEntry[pn].StartingOffset = 0x123; 

      Int64 main_part_size_in_sectors, extra_part_size_in_sectors = 0; 
      main_part_size_in_sectors = (geometry.DiskSize - driveLayoutEx.PartitionEntry[pn].StartingOffset)/geometry.Geometry.BytesPerSector; 

      if (main_part_size_in_sectors <= 0) 
      { 
       return false; 
      } 

      extra_part_size_in_sectors = (MIN_EXTRA_PART_SIZE + bytes_per_track - 1)/bytes_per_track; 
      main_part_size_in_sectors = ((main_part_size_in_sectors/geometry.Geometry.SectorsPerTrack) - 
              extra_part_size_in_sectors) * geometry.Geometry.SectorsPerTrack; 
      if (main_part_size_in_sectors <= 0) 
      { 
       return false; 
      } 

      driveLayoutEx.PartitionEntry[pn].PartitionLength = 50000; 
      driveLayoutEx.PartitionEntry[pn].PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR; 
      driveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x07; 
      driveLayoutEx.PartitionEntry[pn].Mbr.BootIndicator = true; 

      pn++; 

      // Set the optional extra partition 
      // Should end on a track boundary 
      driveLayoutEx.PartitionEntry[pn].StartingOffset = 0x400; 
      driveLayoutEx.PartitionEntry[pn].PartitionLength = 26244; //TODO: Has to change 
      driveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0xef; 

      pn++; 

      for (uint i = 0; i < pn; i++) 
      { 
       driveLayoutEx.PartitionEntry[i].PartitionNumber = i + 1; 
       driveLayoutEx.PartitionEntry[i].PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR; 
       driveLayoutEx.PartitionEntry[i].RewritePartition = true; 
      } 

      driveLayoutEx.PartitionStyle = PARTITION_STYLE.PARTITION_STYLE_MBR; 
      driveLayoutEx.PartitionCount = 4; //It should be a multiple of 4 
      driveLayoutEx.Mbr.Mbr.Signature = createDisk.Mbr.Signature; 




      Marshal.StructureToPtr(driveLayoutEx, driveLayoutbuffer, false); 


      result = DeviceIoControl(handle, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, driveLayoutbuffer, 624, IntPtr.Zero, 0, ref size, IntPtr.Zero); 
      result = DeviceIoControl(handle, IOCTL_DISK_UPDATE_PROPERTIES, IntPtr.Zero, 0, IntPtr.Zero, 0, ref size, IntPtr.Zero); 

      Marshal.FreeHGlobal(driveLayoutbuffer); 
      Marshal.FreeHGlobal(createDiskBuffer); 

      Marshal.FreeHGlobal(lpOutBuffer); 

      return true; 
     } 

Il crée une seule partition avec un décalage à zéro et la longueur de la partition à la taille totale de l'USB. J'essaye ceci des deux derniers jours mais toujours aucune solution.

+0

Même je ne remplir la structure PARTITION_INFORMATION_EX il crée encore une partition. –

Répondre

1

J'ai obtenu la solution.

C'était parce que:

  1. Marshal.AllocHGlobal mémoire allouée est non nul rempli.
  2. PARTITION_INFORMATION_GPT nom de la structure member filled a seulement 8 octets alloués à la place, il nécessite 72 octets.

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] 
public struct PARTITION_INFORMATION_GPT 
{ 
    /// <summary> 
    /// A GUID that identifies the partition type. 
    /// 
    /// Each partition type that the EFI specification supports is identified by its own GUID, which is 
    /// published by the developer of the partition. 
    /// </summary> 
    [FieldOffset(0)] 
    public Guid PartitionType; 

    /// <summary> 
    /// The GUID of the partition. 
    /// </summary> 
    [FieldOffset(16)] 
    public Guid PartitionId; 

    /// <summary> 
    /// The Extensible Firmware Interface (EFI) attributes of the partition. 
    /// 
    /// </summary> 
    [FieldOffset(32)] 
    public UInt64 Attributes; 

    /// <summary> 
    /// A wide-character string that describes the partition. 
    /// </summary> 
    [FieldOffset(40)] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)] 
    public string Name; 
} 
+0

Juste pour vous faire savoir - vous venez de sauver ma vie maintenant! :-) – Tar