1

I'm trying to eject a USB drive in C# after I've copied some files to it.

However, after reading a lot of the examples of how to do that, I can't get anything to work for me.

[DllImport("kernel32.dll")]
public static extern uint GetLastError();

[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr CreateFile
    (string filename, uint desiredAccess,
        uint shareMode, IntPtr securityAttributes,
        int creationDisposition, int flagsAndAttributes,
        IntPtr templateFile);

How I'm calling it:

string path = "\\\\.\\" + driveLetter + ":";

IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, 
  IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

MessageBox.Show(GetLastError().ToString());//gives me zero

My drive letter is K so it just puts that in the string and attempts to open the file (I'm not really sure about that), I'm hoping it will be the drive so that I can eject the USB thumbdrive.

Problem is that handle is always -1

Am I formatting the path string wrong? Or am I using the CreateFile method incorrectly to get a handle to the drive I want to eject?

related:

Eject USB device via C#

Safely remove a USB drive using the Win32 API? (and related links)

Community
  • 1
  • 1
Nateous
  • 757
  • 9
  • 23
  • `GetLastError()` is your friend. p/invoke knows about it, if you set the right attribute. Almost certainly though, you have access denied, because you're asking for overwrite access to a disk that's in use by a mounted filesystem. – Ben Voigt Aug 25 '16 at 20:29
  • it is just returning `0`, but perhaps I'm not using `GetLastError()` correctly? – Nateous Aug 25 '16 at 20:40
  • You are not, it must be Marshal.GetLastWin32Error(). But don't do that either, exceptions are your friend, very much so in a case like this. Throw System.ComponentModel.Win32Exception instead and it takes care of everything. Writing to a disk drive directly does require [super powers](http://stackoverflow.com/a/2818776/17034) given the amount of damage you can do. – Hans Passant Aug 25 '16 at 20:47
  • You'll want to use `Marshal.GetLastWin32Error`. – vcsjones Aug 25 '16 at 20:47
  • let me try that @LeandroTaset because the files are writing fine, but I'm just trying to eject the drive afterwards. – Nateous Aug 25 '16 at 20:50
  • still return `-1` for the `handle`, and `GetLastError()` is still `0` – Nateous Aug 25 '16 at 20:52

1 Answers1

1

Found the answer here (Eject USB device via C#, see Roger Deep's answer)

Short answer:

IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 
    FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, 
    IntPtr.Zero);

I have no idea what the difference is, but it gives me the correct handle to the drive and the rest of the code now works!

Long answer, my complete code to remove a USB drive (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);
Community
  • 1
  • 1
Nateous
  • 757
  • 9
  • 23