public Win32RawDisk(string path, bool writeable = false)
        {
            this.writeable = writeable;
            safeFileHandle = DeviceApi.CreateFile(path,
                                                  writeable ? DeviceApi.GENERIC_READ | DeviceApi.GENERIC_WRITE : DeviceApi.GENERIC_READ,
                                                  writeable ? DeviceApi.FILE_SHARE_READ | DeviceApi.FILE_SHARE_WRITE : DeviceApi.FILE_SHARE_READ,
                                                  IntPtr.Zero,
                                                  DeviceApi.OPEN_EXISTING,
                                                  0,
                                                  IntPtr.Zero);

            if (safeFileHandle.IsInvalid)
            {
                throw new IOException($"Path '{path}' is invalid");
            }

            if (writeable && !LockDevice())
            {
                CloseDevice();
                throw new IOException($"Failed to lock device '{path}'");
            }

            if (writeable && !DismountDevice())
            {
                UnlockDevice();
                CloseDevice();
                throw new IOException("Failed to dismount device '{path}'");
            }
        }
        public static void Read(uint volume, Int64 address, uint length, byte[] data)
        {
            // try to open the current physical drive
            SafeFileHandle hndl = DeviceApi.CreateFile(string.Format("\\\\.\\PhysicalDrive{0}", volume),
                                                       DeviceApi.GENERIC_READ,
                                                       DeviceApi.FILE_SHARE_READ | DeviceApi.FILE_SHARE_WRITE,
                                                       IntPtr.Zero,
                                                       DeviceApi.OPEN_EXISTING,
                                                       DeviceApi.FILE_ATTRIBUTE_READONLY,
                                                       IntPtr.Zero);

            if (!hndl.IsInvalid)
            {
                // set the file pointer to the requested address
                if (DeviceApi.SetFilePointerEx(hndl, address, out _, DeviceApi.EMoveMethod.Begin))
                {
                    // read the requested data from the physical drive
                    uint dummy;
                    if (!DeviceApi.ReadFile(hndl, data, length, out dummy, IntPtr.Zero))
                    {
                        throw new System.IO.IOException("\"ReadFile\" API call failed");
                    }
                }
                else
                {
                    throw new System.IO.IOException("\"SetFilePointerEx\" API call failed");
                }
                hndl.Close();
            }
        }
        public bool UnlockDevice()
        {
            uint intOut = 0;

            return(DeviceApi.DeviceIoControl(safeFileHandle, DeviceApi.FSCTL_UNLOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0,
                                             ref intOut,
                                             IntPtr.Zero));
        }
        public bool DismountDevice()
        {
            uint intOut = 0;

            return(DeviceApi.DeviceIoControl(safeFileHandle, DeviceApi.FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0,
                                             ref intOut,
                                             IntPtr.Zero));
        }
        public long Position()
        {
            if (DeviceApi.SetFilePointerEx(safeFileHandle, 0, out var offset, DeviceApi.EMoveMethod.Current))
            {
                return(offset);
            }
            var error = Marshal.GetLastWin32Error();

            throw new IOException($"Failed to get position, SetFilePointerEx returned Win32 error {error}");
        }
        public uint Write(byte[] buffer)
        {
            if (DeviceApi.WriteFile(safeFileHandle, buffer, Convert.ToUInt32(buffer.Length), out var bytesWritten,
                                    IntPtr.Zero))
            {
                return(bytesWritten);
            }
            var error = Marshal.GetLastWin32Error();

            throw new IOException($"Failed to WriteFile returned Win32 error {error}");
        }
        public long Seek(long offset, SeekOrigin origin)
        {
            if (!Enum.TryParse <DeviceApi.EMoveMethod>(origin.ToString(), out var moveMethod))
            {
                throw new ArgumentOutOfRangeException(nameof(origin));
            }

            if (DeviceApi.SetFilePointerEx(safeFileHandle, offset, out var newOffset, moveMethod))
            {
                return(newOffset);
            }
            var error = Marshal.GetLastWin32Error();

            throw new IOException($"Failed to seek position offset {offset} and origin {origin}, SetFilePointerEx returned Win32 error {error}");
        }
 public void CloseDevice()
 {
     DeviceApi.CloseHandle(safeFileHandle);
 }