为什么在删除多卷USB设备时只有一条WM_DEVICECHANGE消息?

Mik*_*scu 3 usb winapi usb-mass-storage

我正在编写一个应用程序,通过侦听WM_DEVICECHANGE消息来检测何时插入某个USB大容量存储设备以及何时拔下插头.

我还注册了我的应用程序来监听WM_DEVICECHANGE消息DBT_DEVTYP_DEVICEINTERFACE(使用RegisterDeviceNotification API调用),当插入或拔出USB大容量存储设备时,我得到了消息DBT_DEVICEARRIVALDBT_DEVICEREMOVECOMPLETE消息.

现在,当插入具有多个卷的USB设备,然后拔下插头时,会出现问题.

插入设备时,我收到以下消息:

  • WM_DEVICECHANGE(DBT_DEVICEARRIVAL类型DBT_DEVTYP_DEVICEINTERFACE)
  • WM_DEVICECHANGE(DBT_DEVICEARRIVAL类型DBT_DEVTYP_VOLUME)
  • WM_DEVICECHANGE(DBT_DEVICEARRIVAL类型DBT_DEVTYP_VOLUME)

插入时出现以下消息:

  • WM_DEVICECHANGE(DBT_DEVICEREMOVECOMPLETE类型DBT_DEVTYP_VOLUME)
  • WM_DEVICECHANGE(DBT_DEVICEREMOVECOMPLETE类型DBT_DEVTYP_DEVICEINTERFACE)

因此,即使有两个卷,也只有一个删除消息.为什么??

我有两个问题:

  • 如何将DBT_DEVTYP_DEVICEINTERFACE消息与DBT_DEVTYP_VOLUME消息相关联(实质上,我如何知道哪个VOLUME消息对应于哪个DEVICEINTERFACE消息 - 因为我同时获得了设备)?
  • 有没有办法让Windows通知我两个卷删除?

Mik*_*scu 6

好的,所以我能够回答我自己的一个问题:有没有办法让Windows通知我两个卷删除?

是的 - 即使Windows只发送一条DBT_DEVTYP_VOLUME WM_DEVICECHANGE消息,实际上您确实收到了两个卷删除的通知 - 但是,一如既往,答案深埋在MSDN中:

尽管dbcv_unitmask成员可以在任何消息中指定多个卷,但这并不能保证只为指定事件生成一条消息.多个系统组件可以同时独立地为逻辑卷生成消息.

因此,我所要做的就是忽略Microsoft在其中一个示例中提供的示例函数,

char FirstDriveFromMask (ULONG unitmask)
{
   char i;

   for (i = 0; i < 26; ++i)
   {
      if (unitmask & 0x1)
         break;
      unitmask = unitmask >> 1;
   }

   return (i + 'A');
}
Run Code Online (Sandbox Code Playgroud)

并将其替换为解释受影响的所有驱动器的掩码的函数.所以我得到的一条消息确实是两卷,并且掩码中都有两个卷驱动器号.

// [IN] ULONG unitmask
// [IN/OUT] char* outDriveLetters  - an array of characters to be passed in
//                                   that is filled out with the drive letters
//                                   in the mask (this must be 26 bytes to be safe)
// RETURNS the number of drive letters in the mask
int MaskToDriveLetters (ULONG unitmask, char* outDriveLetters)
{
   int cnt = 0;
   for (i = 0; i < 26; ++i)
   {
      if (unitmask & 0x1)
      {
         outDriveLetters[cnt++] = 'A' + i;
         cnt++;
      }
      unitmask = unitmask >> 1;
   }

   outDriveLetters[cnt] = 0; // set the last character to \0 (optional)
   return cnt;  // the number of drives that were set in the mask
}
Run Code Online (Sandbox Code Playgroud)

我仍然有另一个问题要回答 - 两条消息(DBT_DEVTYP_DEVICEINTERFACEDBT_DEVTYP_VOLUME)如何相关?