lydzyw
驱动牛犊
驱动牛犊
  • 注册日期2004-06-28
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分257分
  • 威望40点
  • 贡献值0点
  • 好评度28点
  • 原创分0分
  • 专家分0分
阅读:2708回复:3

将U盘dismount后为什么盘符不消失?

楼主#
更多 发布于:2005-05-27 23:13
请教各位大虾:
    想在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;
}

qiaoroger
驱动牛犊
驱动牛犊
  • 注册日期2005-02-03
  • 最后登录2010-03-22
  • 粉丝0
  • 关注0
  • 积分111分
  • 威望92点
  • 贡献值1点
  • 好评度7点
  • 原创分0分
  • 专家分0分
沙发#
发布于: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);
}

lydzyw
驱动牛犊
驱动牛犊
  • 注册日期2004-06-28
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分257分
  • 威望40点
  • 贡献值0点
  • 好评度28点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2005-05-28 20:19
盘符已消失,分数已送出,非常感谢qiaoroger!

另外,再请教一个问题:
    能否解释一下SHChangeNotify和SendMessageTimeout两个函数各自的用处?是不是前者是通知系统已经发生的事件,而后者是通知正在运行的各种窗口?我试着把SendMessageTimeout注释掉,结果运行后盘符也一样消失.
qiaoroger
驱动牛犊
驱动牛犊
  • 注册日期2005-02-03
  • 最后登录2010-03-22
  • 粉丝0
  • 关注0
  • 积分111分
  • 威望92点
  • 贡献值1点
  • 好评度7点
  • 原创分0分
  • 专家分0分
地板#
发布于:2005-05-30 08:44
盘符已消失,分数已送出,非常感谢qiaoroger!

另外,再请教一个问题:
    能否解释一下SHChangeNotify和SendMessageTimeout两个函数各自的用处?是不是前者是通知系统已经发生的事件,而后者是通知正在运行的各种窗口?我试着把SendMessageTimeout注释掉,结果运行后盘符也一样消失.


这两个函数的意思你还是仔细看MSDN吧。在这个函数里SHChangeNotify是通知系统Shell,SendMessageTimeout是通知all top_level windows.
游客

返回顶部