I am developing a tool which ejects USB drives that doesn't comply with some internal policies. I checked many ways to do the ejection
https://www.codeproject.com/Articles/13530/Eject-USB-disks-using-C
Safely remove a USB drive using the Win32 API?
but all of them were not working for all the USB I tested. After a lot of research and tests, I found this code from StackOverflow which seemed to work fine (last reply) Eject USB device via C#
But recently I got a USB stick which is not ejected.
Surprisingly I debugged the execution and I realized that if I put a breakpoint in the line of DeviceIOControl and I just wait for few second and simply resume the execution, the ejection is done perfectly. If I remove the breakpoint and plug the same USB, the ejection fails. in both cases, the return code of the DeviceIOControl is always TRUE. So, in the end, I test to simply add a Thread.Sleep(3000);
after the DeviceIOControl command and the USB got ejected.
Can anyone explaining what could be happening?
I also detected that there are several similar solutions with different parameters passed to the DeviceIOControl function. Anybody could explain to me which one should I use and why?
Many thanks.
My code:
[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;
public void EjectDrive(string 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;
}
uint dummy = 0;
bool returnvalue = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out dummy, IntPtr.Zero);
Thread.Sleep(3000);
CloseHandle(handle);
// MessageBox.Show("OK to remove drive.");
}