I was looking for a short way to eject USB-devices via C#-code, so I coded a little class myself, yet it simply doesn't work. Since there's no popup that says "Lock success!" I assume that the problem relies within the "LockVolume"-function, but I don't know where.
Does anybody see the mistake I made?
class USBEject
{
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
private IntPtr handle = IntPtr.Zero;
const int GENERIC_READ = 0x80000000;
const int GENERIC_WRITE = 0x40000000;
const int FILE_SHARE_READ = 0x1;
const int FILE_SHARE_WRITE = 0x2;
const int FSCTL_LOCK_VOLUME = 0x00090018;
const int FSCTL_DISMOUNT_VOLUME = 0x00090020;
const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804;
/// <summary>
/// Constructor for the USBEject class
/// </summary>
/// <param name="driveLetter">This should be the drive letter. Format: F:/, C:/..</param>
public USBEject(string driveLetter)
{
string filename = @"\\.\" + driveLetter[0] + ":";
handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
}
public bool Eject()
{
if (LockVolume(handle) && DismountVolume(handle))
{
PreventRemovalOfVolume(handle, false);
return AutoEjectVolume(handle);
}
return false;
}
private bool LockVolume(IntPtr handle)
{
uint byteReturned;
for (int i = 0; i < 10; i++)
{
if (DeviceIoControl(handle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero))
{
System.Windows.Forms.MessageBox.Show("Lock success!");
return true;
}
Thread.Sleep(500);
}
return false;
}
private bool PreventRemovalOfVolume(IntPtr handle, bool prevent)
{
byte[] buf = new byte[1];
uint retVal;
buf[0] = (prevent) ? (byte)1 : (byte)0;
return DeviceIoControl(handle, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
}
private bool DismountVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool AutoEjectVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool CloseVolume(IntPtr handle)
{
return CloseHandle(handle);
}
}
Locate your external storage device's icon on the desktop. Drag the icon to the Trash bin, which will change to an Eject icon. Alternatively, hold the "Ctrl" key and left-click your mouse on the external drive's icon. Click Eject on the pop-up menu.
With Command+E keyboard shortcut Locate the USB flash drive on your desktop. Click it once to select it. On your keyboard, press Command + E to eject the flash drive.
If you can't find the Safely Remove Hardware icon, press and hold (or right-click) the taskbar and select Taskbar settings . Under Notification Area, choose Select which icons appear on the taskbar. Scroll to Windows Explorer: Safely Remove Hardware and Eject Media and turn it on.
Changed just a little bit your code and it goes as follows:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
private IntPtr handle = IntPtr.Zero;
const uint GENERIC_READ = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const int FILE_SHARE_READ = 0x1;
const int FILE_SHARE_WRITE = 0x2;
const int FSCTL_LOCK_VOLUME = 0x00090018;
const int FSCTL_DISMOUNT_VOLUME = 0x00090020;
const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804;
/// <summary>
/// Constructor for the USBEject class
/// </summary>
/// <param name="driveLetter">This should be the drive letter. Format: F:/, C:/..</param>
public IntPtr USBEject(string driveLetter)
{
string filename = @"\\.\" + driveLetter[0] + ":";
return CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
}
public bool Eject(IntPtr handle)
{
bool result = false;
if (LockVolume(handle) && DismountVolume(handle))
{
PreventRemovalOfVolume(handle, false);
result = AutoEjectVolume(handle);
}
CloseHandle(handle);
return result;
}
private bool LockVolume(IntPtr handle)
{
uint byteReturned;
for (int i = 0; i < 10; i++)
{
if (DeviceIoControl(handle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero))
{
System.Windows.Forms.MessageBox.Show("Lock success!");
return true;
}
Thread.Sleep(500);
}
return false;
}
private bool PreventRemovalOfVolume(IntPtr handle, bool prevent)
{
byte[] buf = new byte[1];
uint retVal;
buf[0] = (prevent) ? (byte)1 : (byte)0;
return DeviceIoControl(handle, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
}
private bool DismountVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool AutoEjectVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool CloseVolume(IntPtr handle)
{
return CloseHandle(handle);
}
So you can use it in two ways:
handle = USBEject("D:");
Eject(handle);
or directly:
Eject(USBEject("D:"));
It works for me on my Windows 10 machine (preview 14291)
Found the answer for my issue by using some of Roger Deep's code for the CreateFile
call.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
EjectDrive('K');
}
void EjectDrive(char driveLetter)
{
string path = @"\\.\" + driveLetter + @":";
IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
if ((long)handle == -1)
{
MessageBox.Show("Unable to open drive " + driveLetter);
return;
}
int dummy = 0;
DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0,
IntPtr.Zero, 0, ref dummy, IntPtr.Zero);
CloseHandle(handle);
MessageBox.Show("OK to remove drive.");
}
[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr CreateFile
(string filename, uint desiredAccess,
uint shareMode, IntPtr securityAttributes,
int creationDisposition, int flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32")]
private static extern int DeviceIoControl
(IntPtr deviceHandle, uint ioControlCode,
IntPtr inBuffer, int inBufferSize,
IntPtr outBuffer, int outBufferSize,
ref int bytesReturned, IntPtr overlapped);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With