阅读:2708回复:3
将U盘dismount后为什么盘符不消失?
请教各位大虾:
想在user mode中编程使U盘可以被安全拔除(就象windows自带的安全删除硬件功能一样),但是我调用下面的EjectVolume函数却不能使U盘盘符消失,为什么? LPTSTR szVolumeFormat = TEXT(\"\\\\\\\\.\\\\%c:\"); LPTSTR szRootFormat = TEXT(\"%c:\\\\\"); HANDLE OpenVolume(TCHAR cDriveLetter); BOOLEAN LockVolume(HANDLE hVolume); BOOLEAN DismountVolume(HANDLE hVolume); BOOLEAN PreventRemovalOfVolume(HANDLE hVolume, BOOLEAN fPrevent); BOOLEAN AutoEjectVolume(HANDLE hVolume); BOOLEAN CloseVolume(HANDLE hVolume); HANDLE OpenVolume(TCHAR cDriveLetter) { HANDLE hVolume; UINT uDriveType; TCHAR szVolumeName[8]; TCHAR szRootName[5]; DWORD dwAccessFlags; CString mbText,mbTitle; wsprintf(szRootName, szRootFormat, cDriveLetter); uDriveType = GetDriveType(szRootName); switch(uDriveType) { case DRIVE_REMOVABLE: dwAccessFlags = GENERIC_READ | GENERIC_WRITE; break; case DRIVE_CDROM: dwAccessFlags = GENERIC_READ; break; default: mbText=_T(\"设备类型错误!\"); mbTitle=_T(\"提示\"); MessageBox(NULL,LPCTSTR(mbText),LPCTSTR(mbTitle),MB_OK); return INVALID_HANDLE_VALUE; } wsprintf(szVolumeName, szVolumeFormat, cDriveLetter); hVolume = CreateFile( szVolumeName, dwAccessFlags, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (hVolume == INVALID_HANDLE_VALUE) { mbText=_T(\"设备不存在!\"); mbTitle=_T(\"提示\"); MessageBox(NULL,LPCTSTR(mbText),LPCTSTR(mbTitle),MB_OK); } return hVolume; } BOOLEAN CloseVolume(HANDLE hVolume) { return CloseHandle(hVolume); } BOOLEAN LockVolume(HANDLE hVolume) { DWORD dwBytesReturned; DWORD dwSleepAmount; int nTryCount; dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES; // Do this in a loop until a timeout period has expired for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) { if (DeviceIoControl(hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) return TRUE; Sleep(dwSleepAmount); } return FALSE; } BOOLEAN DismountVolume(HANDLE hVolume) { DWORD dwBytesReturned; return DeviceIoControl( hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL); } BOOLEAN PreventRemovalOfVolume(HANDLE hVolume, BOOLEAN fPreventRemoval) { DWORD dwBytesReturned; PREVENT_MEDIA_REMOVAL PMRBuffer; PMRBuffer.PreventMediaRemoval = fPreventRemoval; return DeviceIoControl( hVolume, IOCTL_STORAGE_MEDIA_REMOVAL, &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL), NULL, 0, &dwBytesReturned, NULL); } BOOLEAN AutoEjectVolume(HANDLE hVolume) { DWORD dwBytesReturned; return DeviceIoControl( hVolume, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytesReturned, NULL); } BOOLEAN EjectVolume(TCHAR cDriveLetter) { HANDLE hVolume; BOOLEAN fRemoveSafely = FALSE; BOOLEAN fAutoEject = FALSE; CString mbText,mbTitle; // Open the volume. hVolume = OpenVolume(cDriveLetter); if (hVolume == INVALID_HANDLE_VALUE) return FALSE; // Lock and dismount the volume. if (LockVolume(hVolume) && DismountVolume(hVolume)) { fRemoveSafely = TRUE; // Set prevent removal to false and eject the volume. if (PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume)) fAutoEject = TRUE; } // Close the volume so other processes can use the drive. if (!CloseVolume(hVolume)) return FALSE; if (fAutoEject) { mbText=_T(\"设备已安全弹出!\"); mbTitle=_T(\"提示\"); MessageBox(NULL,LPCTSTR(mbText),LPCTSTR(mbTitle),MB_OK); } else { if (fRemoveSafely) { mbText=_T(\"设备可以安全移除!\"); mbTitle=_T(\"提示\"); MessageBox(NULL,LPCTSTR(mbText),LPCTSTR(mbTitle),MB_OK); } else { mbText=_T(\"设备正在进行数据传输,请稍后重试!\"); mbTitle=_T(\"提示\"); MessageBox(NULL,LPCTSTR(mbText),LPCTSTR(mbTitle),MB_OK); } } return TRUE; } |
|
沙发#
发布于:2005-05-28 16:41
Dismount后应该发广播消息吧?
偶做虚拟盘的时候在MOUNT后调用 BroadcastDeviceChange( DBT_DEVICEARRIVAL, nDriverNo, 0 ); Dismount后调用: BroadcastDeviceChange( DBT_DEVICEREMOVECOMPLETE, nDriverNo, 0 ); void BroadcastDeviceChange( WPARAM message, int nDosDriveNo, DWORD driveMap ) { DEV_BROADCAST_VOLUME dbv; char root[] = {0, \':\', \'\\\\\', 0 }; DWORD dwResult; LONG event = 0; int i; if (message == DBT_DEVICEARRIVAL) event = SHCNE_DRIVEADD; if (message == DBT_DEVICEREMOVECOMPLETE) event = SHCNE_DRIVEREMOVED; if (driveMap == 0) { root[0] = nDosDriveNo + \'A\'; SHChangeNotify(event, SHCNF_PATH, root, NULL); } else { for (i = 0; i < 26; i++) { if (driveMap & (1 << i)) { root[0] = i + \'A\'; SHChangeNotify(event, SHCNF_PATH, root, NULL); } } } dbv.dbcv_size = sizeof(dbv); dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME; dbv.dbcv_reserved = 0; dbv.dbcv_unitmask = (driveMap != 0) ? driveMap : (1 << nDosDriveNo); dbv.dbcv_flags = 0; SendMessageTimeout (HWND_BROADCAST, WM_DEVICECHANGE, message, (LPARAM)(&dbv), 0, 500, &dwResult); } |
|
板凳#
发布于:2005-05-28 20:19
盘符已消失,分数已送出,非常感谢qiaoroger!
另外,再请教一个问题: 能否解释一下SHChangeNotify和SendMessageTimeout两个函数各自的用处?是不是前者是通知系统已经发生的事件,而后者是通知正在运行的各种窗口?我试着把SendMessageTimeout注释掉,结果运行后盘符也一样消失. |
|
地板#
发布于:2005-05-30 08:44
盘符已消失,分数已送出,非常感谢qiaoroger! 这两个函数的意思你还是仔细看MSDN吧。在这个函数里SHChangeNotify是通知系统Shell,SendMessageTimeout是通知all top_level windows. |
|