2015-01-09 99 views
1

我正在使用Win32 API(我通常不使用它)在用戶請求上以編程方式彈出USB設備。從上下搜索網頁,下面的代碼就是我想到的。你可以看到,我的CreateFile()調用用於爲dwIoControlCode參數傳遞GENERIC_READ | GENERIC_WRITE,但是當我調試時,我得到了一個值爲INVALID_HANDLE_VALUE的句柄。在我對FormatMessage()的調用中,GetLastError()調用返回了一個代碼,該代碼翻譯爲「訪問被拒絕」。環顧四周,我看到有人說通過0而不是GENERIC_READ | GENERIC_WRITE。我試過了,我得到了一個句柄,不再是一個不好的句柄值。使用非錯誤句柄值,我繼續使用後續代碼。使用CreateFile訪問USB以彈出 - 不能正常工作

下一次調用DeviceIoControl()(GetHandleInformation()和DeviceIoControl稍後出於調試目的),將dwIoControlCode參數傳遞給FSCTL_LOCK_VOLUME,並將調用返回false,並將GetLastError( )返回代碼翻譯爲「錯誤的功能」。我在此之前插入了調用GetHandleInformation()和DeviceIoControl(...,IOCTL_STORAGE_CHECK_VERIFY,...)以檢查我的句柄。 GetHandleInformation()返回true,所以聽起來不錯。但是,DeviceIoControl(...,IOCTL_STORAGE_CHECK_VERIFY,...)返回false,GetLastError()返回代碼轉換爲「Access is denied」。我還沒有能夠通過這一點。

這個代碼或其變種,是由互聯網上的許多人建議,但它不適合我。我希望有人能指出我要去哪裏錯了。我使用MSVC2010編譯器在Win7 64位上進行編譯。

感謝您的任何幫助。

#include <windows.h> 

void ejectDrive(char driveletter) 
{ 
    DWORD dwRet = 0; 
    DWORD retSize; 
    LPTSTR pTemp=NULL; 
    bool ok = false; 
    char devicepath[7]; 
    char format[] = "\\\\.\\?:"; 
    wchar_t wtext[7]; 

    strcpy_s(devicepath, format); 
    devicepath[4] = driveletter; 
    mbstowcs(wtext, devicepath,strlen(devicepath)+1); 

    HANDLE hVol = CreateFile(wtext, 0 /*GENERIC_READ | GENERIC_WRITE*/, 
          FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, 
          OPEN_EXISTING, 0, NULL); 
    if (hVol == INVALID_HANDLE_VALUE) 
    { 
     retSize=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| 
           FORMAT_MESSAGE_FROM_SYSTEM| 
           FORMAT_MESSAGE_ARGUMENT_ARRAY, 
           NULL, 
           GetLastError(), 
           LANG_NEUTRAL, 
           (LPTSTR)&pTemp, 
           0, 
           NULL); 
     return; 
    } 

    LPDWORD lpdwFlags; 
    ok = GetHandleInformation(hVol, lpdwFlags); 
    retSize=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| 
          FORMAT_MESSAGE_FROM_SYSTEM| 
          FORMAT_MESSAGE_ARGUMENT_ARRAY, 
          NULL, 
          GetLastError(), 
          LANG_NEUTRAL, 
          (LPTSTR)&pTemp, 
          0, 
          NULL); 

    ok = DeviceIoControl(hVol, IOCTL_STORAGE_CHECK_VERIFY, NULL,0,NULL, 0, lpdwFlags, 0); 
    if(!ok) 
    { 
     retSize=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| 
           FORMAT_MESSAGE_FROM_SYSTEM| 
           FORMAT_MESSAGE_ARGUMENT_ARRAY, 
           NULL, 
           GetLastError(), 
           LANG_NEUTRAL, 
           (LPTSTR)&pTemp, 
           0, 
           NULL); 
     return; 
    } 

    ok = DeviceIoControl(hVol, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &dwRet, 0); 
    if(!ok) 
    { 
     retSize=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| 
           FORMAT_MESSAGE_FROM_SYSTEM| 
           FORMAT_MESSAGE_ARGUMENT_ARRAY, 
           NULL, 
           GetLastError(), 
           LANG_NEUTRAL, 
           (LPTSTR)&pTemp, 
           0, 
           NULL); 
     return; 
    } 

    if(!DeviceIoControl(hVol, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, &dwRet, 0)) 
    { 
     return; 
    } 

    DeviceIoControl(hVol, IOCTL_STORAGE_EJECT_MEDIA, 0, 0, 0, 0, &dwRet, 0); 

    CloseHandle(hVol); 
} 
+1

嘗試用'GENERIC_READ'打開句柄。另請注意,只有媒體可訪問時,DeviceIoControl纔會返回true(根據[IOCTL_STORAGE_CHECK_VERIFY文檔](http://msdn.microsoft.com/zh-cn/library/windows/desktop/aa363404%28v=vs)。 85%29.aspx))。 – 2015-01-09 20:24:39

+0

根據http://stackoverflow.com/q/3918248/103167您將需要'GENERIC_READ | GENERIC_WRITE'來執行彈出操作。因此,通過在具有足夠設備權限的用戶上下文中運行而不是通過打開0訪問來解決'CreateFile'故障。 – 2015-01-09 20:36:42

+0

另外,您可能需要打開PhysicalDrive設備,而不是音量。 – 2015-01-09 20:37:29

回答

0

我在我的項目中使用了一個解決方案,我在this SO answer中更詳細地寫出了這個解決方案。

但是,我沒有修改調用基於看到CreateFile —你今年—早些時候SO質疑下面的簽名:

// C# 
hVolume = CreateFile(@"\\.\A:", GENERIC_READ, 
           FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 
           OPEN_EXISTING, 0, IntPtr.Zero); 

我的應用程序中調用這個運行沒有提升的權限,併成功彈出驅動器。