今天在修chomium的BUG: issue 325157时, 发现对可移动设备操作eject(弹出)和safely remove(安全移除)两者是不同,以前还没仔细留意过这两者区别。

chromium这个BUG是storage.eject API调用结果似乎不对,使用该API eject设备后,storage.getInfo仍然返回被eject设备信息,并且onDetach事件也没有被触发。按照我们理解,eject设备就是把从当前操作系统中弹出,getInfo不应再返回设备信息,onDetach事件应被触发。

storage.eject API在windows平台下是通过发送IOCTL_STORAGE_EJECT_MEDIA状态码给DeviceIoControl函数实现的。onDetach事件是通过监听windows的WM_DEVICECHANGE消息,获取其中的DBT_DEVICEREMOVECOMPLETE事件。从issue的运行结果来看,调用DeviceIoControl并不会触发windows下的DBT_DEVICEREMOVECOMPLETE事件。这是getInfo和onDetach没有改变的原因

为什么eject API不会触发remove事件呢?经过一番调研后发现,safely remove和eject是有些不同的,eject是会仍然保留设备与系统连接,而safely remove则是直接断开,物理地断开了;只有safely remove才会触发该事件。更详细的不同,点这里

在windows下,

  • eject操作:右键设备盘符 -> eject,会发现盘符还在,但是双击它却没反应。
  • safely remove: 在右下角消息栏有一个usb的设备管理图标,右键它->safely remove hardware. 此时在我的电脑会发现盘符彻底没有了。

对于两者具体在编程的是使用不同的API,具体可以看这里:

  • eject: DeviceIoControl函数
  • safely remove: CM_Request_Device_Eject函数

在linux和mac下又有不同,safely remove前最好先eject一下,因为在linux,mac下有writing cache, eject会把cache数据sync到设备中。而windows默认是关闭writing cache的。另外,eject一般是对media,如CD, DVD, 而safely remove则是对USB设备。