C# - Ejecting USB drive using DeviceIoControl command - Failing in some cases

1

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.");
    }
.net
usb
asked on Stack Overflow Jan 10, 2017 by YaKs • edited May 30, 2019 by Bhargav Rao

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0