Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eject USB device via C#

Tags:

c#

usb

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);
    }
}
like image 864
lukew Avatar asked Oct 09 '11 15:10

lukew


People also ask

How do I eject my USB C?

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.

What is the shortcut key for Eject USB?

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.

How do I eject a USB without the eject button?

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.


2 Answers

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)

like image 113
Roger Deep Avatar answered Oct 26 '22 03:10

Roger Deep


Found the answer for my issue by using some of Roger Deep's code for the CreateFile call.

My code to remove a USB drive inside WPF Window:

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);
like image 3
Nateous Avatar answered Oct 26 '22 02:10

Nateous