public static extern bool DeviceIoControl(SafeFileHandle hVol , int controlCode , IntPtr inBuffer , int inBufferSize , ref DiskExtents outBuffer , int outBufferSize , ref int bytesReturned , IntPtr overlapped);
public static extern bool DeviceIoControl( IntPtr hDevice, UInt32 dwIoControlCode, IntPtr lpInBuffer, Int32 nInBufferSize, ref DiskExtents lpOutBuffer, Int32 nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
public void Dispose() { try { var de1 = new DiskExtents(); var bytesReturned = 0; if (!DeviceIoControl(diskHandle, DeviceIoControlCode.FSCTL_UNLOCK_VOLUME, IntPtr.Zero, 0, ref de1, Marshal.SizeOf(de1), ref bytesReturned, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "FSCTL_LOCK_VOLUME"); } //fileStream.Dispose(); diskHandle.Dispose(); } catch (Exception e) { if (!e.Message.StartsWith("External component has thrown an exception.")) { throw; } } }
// A Volume could be on many physical drives. // Returns a list of string containing each physical drive the volume uses. // For CD Drives with no disc in it will return an empty list. private List <string> GetPhysicalDriveStrings(DriveInfo driveInfo) { SafeFileHandle sfh = null; List <string> physicalDrives = new List <string>(1); string path = "\\\\.\\" + driveInfo.RootDirectory.ToString().TrimEnd('\\'); try { sfh = NativeMethods.CreateFile(path, 0, FileShareRead | Filesharewrite, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero); int bytesReturned = 0; DiskExtents de1 = new DiskExtents(); int numDiskExtents = 0; bool result = NativeMethods.DeviceIoControl(sfh , IoctlVolumeGetVolumeDiskExtents , IntPtr.Zero , 0 , ref de1 , Marshal.SizeOf(de1) , ref bytesReturned, IntPtr.Zero); DiskExtents de1Cast = (DiskExtents)de1; if (result == true) { // there was only one disk extent. So the volume lies on 1 physical drive. physicalDrives.Add("\\\\.\\PhysicalDrive" + de1Cast.first.DiskNumber.ToString()); return(physicalDrives); } if (Marshal.GetLastWin32Error() == IncorrectFunction) { // The drive is removable and removed, like a CDRom with nothing in it. return(physicalDrives); } if (Marshal.GetLastWin32Error() == MoreDataIsAvailable) { // This drive is part of a mirror or volume - handle it below. } else if (Marshal.GetLastWin32Error() != ErrorInsufficientBuffer) { throw new Win32Exception(); } // Houston, we have a spanner. The volume is on multiple disks. // Untested... // We need a blob of memory for the DISK_EXTENTS structure, and all the DISK_EXTENTS int blobSize = Marshal.SizeOf(typeof(DiskExtents)) + (de1Cast.numberOfExtents - 1) * Marshal.SizeOf(typeof(DiskExtent)); IntPtr pBlob = Marshal.AllocHGlobal(blobSize); result = NativeMethods.DeviceIoControl(sfh, IoctlVolumeGetVolumeDiskExtents, IntPtr.Zero, 0, pBlob, blobSize, ref bytesReturned, IntPtr.Zero); if (result == false) { throw new Win32Exception(); } // Read them out one at a time. IntPtr pNext = new IntPtr(pBlob.ToInt64() + 8); // is this always ok on 64 bit OSes? ToInt64? for (int i = 0; i <= de1Cast.numberOfExtents - 1; i++) { DiskExtent diskExtentN = (DiskExtent)Marshal.PtrToStructure(pNext, typeof(DiskExtent)); physicalDrives.Add("\\\\.\\PhysicalDrive" + diskExtentN.DiskNumber.ToString()); pNext = new IntPtr(pNext.ToInt32() + Marshal.SizeOf(typeof(DiskExtent))); } return(physicalDrives); } finally { if (sfh != null) { if (sfh.IsInvalid == false) { sfh.Close(); } sfh.Dispose(); } } }
public SDManagement(String RootDir) { var de1 = new DiskExtents(); var bytesReturned = 0; try { driveLetter = RootDir; var path = @"\\.\" + driveLetter; using (var sfh = CreateFile(path, EFileAccess.GenericRead | EFileAccess.GenericWrite, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, 0, IntPtr.Zero)) { if (sfh.IsInvalid) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Handle.IsInvalid"); } using (new FileStream(sfh, FileAccess.Read)) { if (DeviceIoControl(sfh, DeviceIoControlCode.IoctlVolumeGetVolumeDiskExtents, IntPtr.Zero, 0, ref de1, Marshal.SizeOf(de1), ref bytesReturned, IntPtr.Zero)) { SDPhysicalName = @"\\.\PhysicalDrive" + de1.first.DiskNumber.ToString(CultureInfo.InvariantCulture); var dg1 = new DISK_GEOMETRY(); if (!DeviceIoControl(sfh, DeviceIoControlCode.IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0, ref dg1, Marshal.SizeOf(dg1), ref bytesReturned, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "IOCTL_DISK_GET_DRIVE_GEOMETRY"); } SDSize = dg1.DiskSize; if (!DeviceIoControl(sfh, DeviceIoControlCode.FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, ref de1, Marshal.SizeOf(de1), ref bytesReturned, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "FSCTL_LOCK_VOLUME"); } if (!DeviceIoControl(sfh, DeviceIoControlCode.FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, ref de1, Marshal.SizeOf(de1), ref bytesReturned, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "FSCTL_DISMOUNT_VOLUME"); } //if (IsWinVistaOrHigher()) { deviceName = GetDeviceName(driveLetter); if (!String.IsNullOrEmpty(deviceName) && !DefineDosDevice(EParam.DDD_RAW_TARGET_PATH | EParam.DDD_REMOVE_DEFINITION | EParam.DDD_EXACT_MATCH_ON_REMOVE, driveLetter, deviceName)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "DefineDosDevice"); } } } var lerror = Marshal.GetLastWin32Error(); if (lerror != 0) { if (lerror == 1) { throw new Win32Exception(lerror, String.Format(@"IncorrectFunction The drive ""{0}"" is removable and removed, like a CDRom with nothing in it.)", driveLetter)); } if (lerror == 122) { throw new Win32Exception(lerror, "ErrorInsufficientBuffer"); } throw new NotSupportedException("Multiple Disc Volume"); } } } } catch (Exception e) { if (!e.Message.StartsWith("External component has thrown an exception.")) { throw; } } diskHandle = CreateFile(SDPhysicalName, EFileAccess.GenericRead | EFileAccess.GenericWrite, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.Device | EFileAttributes.NoBuffering | EFileAttributes.Write_Through, IntPtr.Zero); if (diskHandle.IsInvalid) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Handle.IsInvalid"); } if (!DeviceIoControl(diskHandle, DeviceIoControlCode.FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, ref de1, Marshal.SizeOf(de1), ref bytesReturned, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "FSCTL_LOCK_VOLUME"); } fileStream = new FileStream(diskHandle, FileAccess.ReadWrite); }