使用C#在USB上创建多个分区

我试图使用DeviceIOControl在USB中创建多个partiions。 它始终只创建一个分区。

这是我的源代码

[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; ///  /// Describes the geometry of disk devices and media. ///  [StructLayout(LayoutKind.Explicit)] public struct DISK_GEOMETRY { ///  /// The number of cylinders. ///  [FieldOffset(0)] public Int64 Cylinders; ///  /// The type of media. For a list of values, see MEDIA_TYPE. ///  [FieldOffset(8)] public MEDIA_TYPE MediaType; ///  /// The number of tracks per cylinder. ///  [FieldOffset(12)] public uint TracksPerCylinder; ///  /// The number of sectors per track. ///  [FieldOffset(16)] public uint SectorsPerTrack; ///  /// The number of bytes per sector. ///  [FieldOffset(20)] public uint BytesPerSector; } ///  /// Describes the extended geometry of disk devices and media. ///  [StructLayout(LayoutKind.Explicit)] private struct DISK_GEOMETRY_EX { ///  /// A DISK_GEOMETRY structure. ///  [FieldOffset(0)] public DISK_GEOMETRY Geometry; ///  /// The disk size, in bytes. ///  [FieldOffset(24)] public Int64 DiskSize; ///  /// Any additional data. ///  [FieldOffset(32)] public Byte Data; } ///  /// Represents the format of a partition. ///  public enum PARTITION_STYLE : uint { ///  /// Master boot record (MBR) format. ///  PARTITION_STYLE_MBR = 0, ///  /// GUID Partition Table (GPT) format. ///  PARTITION_STYLE_GPT = 1, ///  /// Partition not formatted in either of the recognized formats—MBR or GPT. ///  PARTITION_STYLE_RAW = 2 } ///  /// Contains partition information specific to master boot record (MBR) disks. ///  [StructLayout(LayoutKind.Explicit)] public struct PARTITION_INFORMATION_MBR { #region Constants ///  /// An unused entry partition. ///  public const byte PARTITION_ENTRY_UNUSED = 0x00; ///  /// A FAT12 file system partition. ///  public const byte PARTITION_FAT_12 = 0x01; ///  /// A FAT16 file system partition. ///  public const byte PARTITION_FAT_16 = 0x04; ///  /// An extended partition. ///  public const byte PARTITION_EXTENDED = 0x05; ///  /// An IFS partition. ///  public const byte PARTITION_IFS = 0x07; ///  /// A FAT32 file system partition. ///  public const byte PARTITION_FAT32 = 0x0B; ///  /// A logical disk manager (LDM) partition. ///  public const byte PARTITION_LDM = 0x42; ///  /// An NTFT partition. ///  public const byte PARTITION_NTFT = 0x80; ///  /// 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. ///  public const byte PARTITION_VALID_NTFT = 0xC0; #endregion ///  /// The type of partition. For a list of values, see Disk Partition Types. ///  [FieldOffset(0)] [MarshalAs(UnmanagedType.U1)] public byte PartitionType; ///  /// If this member is TRUE, the partition is bootable. ///  [FieldOffset(1)] [MarshalAs(UnmanagedType.I1)] public bool BootIndicator; ///  /// If this member is TRUE, the partition is of a recognized type. ///  [FieldOffset(2)] [MarshalAs(UnmanagedType.I1)] public bool RecognizedPartition; ///  /// The number of hidden sectors in the partition. ///  [FieldOffset(4)] public uint HiddenSectors; } ///  /// Contains GUID partition table (GPT) partition information. ///  [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] public struct PARTITION_INFORMATION_GPT { ///  /// 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. ///  [FieldOffset(0)] public Guid PartitionType; ///  /// The GUID of the partition. ///  [FieldOffset(16)] public Guid PartitionId; ///  /// The Extensible Firmware Interface (EFI) attributes of the partition. /// ///  [FieldOffset(32)] public UInt64 Attributes; ///  /// A wide-character string that describes the partition. ///  [FieldOffset(40)] public string Name; } ///  /// Provides information about a drive's master boot record (MBR) partitions. ///  [StructLayout(LayoutKind.Explicit)] private struct DRIVE_LAYOUT_INFORMATION_MBR { ///  /// The signature of the drive. ///  [FieldOffset(0)] public uint Signature; } ///  /// Contains information about a drive's GUID partition table (GPT) partitions. ///  [StructLayout(LayoutKind.Explicit)] private struct DRIVE_LAYOUT_INFORMATION_GPT { ///  /// The GUID of the disk. ///  [FieldOffset(0)] public Guid DiskId; ///  /// The starting byte offset of the first usable block. ///  [FieldOffset(16)] public Int64 StartingUsableOffset; ///  /// The size of the usable blocks on the disk, in bytes. ///  [FieldOffset(24)] public Int64 UsableLength; ///  /// The maximum number of partitions that can be defined in the usable block. ///  [FieldOffset(32)] public uint MaxPartitionCount; } ///  /// Contains information about a disk partition. ///  [StructLayout(LayoutKind.Explicit)] public struct PARTITION_INFORMATION_EX { ///  /// The format of the partition. For a list of values, see PARTITION_STYLE. ///  [FieldOffset(0)] public PARTITION_STYLE PartitionStyle; ///  /// The starting offset of the partition. ///  [FieldOffset(8)] public Int64 StartingOffset; ///  /// The length of the partition, in bytes. ///  [FieldOffset(16)] public Int64 PartitionLength; ///  /// The number of the partition (1-based). ///  [FieldOffset(24)] public uint PartitionNumber; ///  /// 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. ///  [FieldOffset(28)] [MarshalAs(UnmanagedType.I1)] public bool RewritePartition; ///  /// 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. ///  [FieldOffset(32)] public PARTITION_INFORMATION_MBR Mbr; ///  /// 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. ///  [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; } ///  /// Contains extended information about a drive's partitions. ///  [StructLayout(LayoutKind.Explicit)] private struct DRIVE_LAYOUT_INFORMATION_EX { ///  /// The style of the partitions on the drive enumerated by the PARTITION_STYLE enumeration. ///  [FieldOffset(0)] public PARTITION_STYLE PartitionStyle; ///  /// 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. ///  [FieldOffset(4)] public uint PartitionCount; ///  /// A DRIVE_LAYOUT_INFORMATION_MBR structure containing information about the master boot record type /// partitioning on the drive. ///  [FieldOffset(8)] public DRIVE_LAYOUT_INFORMATION_UNION Mbr; ///  /// A DRIVE_LAYOUT_INFORMATION_GPT structure containing information about the GUID disk partition type /// partitioning on the drive. ///  // [FieldOffset(8)] //public DRIVE_LAYOUT_INFORMATION_GPT Gpt; ///  /// A variable-sized array of PARTITION_INFORMATION_EX structures, one structure for each partition on the /// drive. ///  [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; } 

它只创建一个偏移为零的分区,并将分区长度设置为USB的完整大小。

我试过这两天,但仍然没有解决方案。

我得到了解决方案。

这是因为:

  1. Marshal.AllocHGlobal分配的内存不是零填充。
  2. PARTITION_INFORMATION_GPT结构名称成员填充只分配了8个字节的内存,而它需要72个字节。

 [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] public struct PARTITION_INFORMATION_GPT { ///  /// 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. ///  [FieldOffset(0)] public Guid PartitionType; ///  /// The GUID of the partition. ///  [FieldOffset(16)] public Guid PartitionId; ///  /// The Extensible Firmware Interface (EFI) attributes of the partition. /// ///  [FieldOffset(32)] public UInt64 Attributes; ///  /// A wide-character string that describes the partition. ///  [FieldOffset(40)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)] public string Name; }