Creating multiple partitions on USB using C#

匿名 (未验证) 提交于 2019-12-03 07:36:14

问题:

Iam trying to use DeviceIOControl to create multiple partiions in USB. It is always creating only one partition.

Here is my source code

[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;         } 

It only creates one partition with offset to zero and partition length to full size of USB.

Iam trying this from past two days but still no solution.

回答1:

I got the Solution.

It was because:

  1. Marshal.AllocHGlobal allocated memory is not zero filled.
  2. PARTITION_INFORMATION_GPT structure name member filled is only has 8 bytes of memory allocated instead it requires 72 bytes.

[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; } 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!