jsctypes - problems using SHChangeNotifyRegister for MEDIA/DRIVE events

谁说胖子不能爱 提交于 2019-12-05 09:27:00

For anyone else looking to do this, I'm posting a nasty hack of a work-around. (I won't accept this answer, in the hope that eventually someone will post how to do it properly).


After extensive reading, the only other recommended way I could of enumerating and/or determining the status of USB volumes was using WMI. The following WQL query did the trick:

select Caption, Size from win32_LogicalDisk where DriveType = 2

To use WQL from C++, you have to use COM. Using that from js-ctypes is not insignificant engineering task. You need to arrange for the DLL to be loaded and used from a ChromeWorker and sometimes I found that I specifically needed to make sure that JavaScript callback functions were being called from the correct Firefox thread, and that COM is not initialised in a multithreaded apartment.

Caption is the drive letter. It would seem that once a USB drive is ejected Size reports as zero.

It was then reasonably simple to call this in a polling loop inside the ChromeWorker thread, model the changes to the mounted volumes, and raise synthetic USB-Mounted/Ejected/Removed events in my DOM windows.


Unfortunately, there was one huge problem with this. If you insert a USB flash drive it generally takes between 2 and 30 seconds (depending on size) to be mounted by Windows. During that time (particularly after the 1st second or so), if you run the above WQL query, it will BLOCK THE USB VOLUME FROM BEING MOUNTED BY THE OPERATING SYSTEM (?!?) Effectively causing a denial of service.

However much incredulity this caused me, after enquiring I was assured that if I used asynchronous (rather than synchronous or semisynchronous) WQL queries, that the denial of service would not occur.

SELECT * FROM __instanceoperationevent WITHIN 2 
WHERE TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 2

If the __instanceoperationevent ISA __InstanceCreationEvent then the volume was added. If the __instanceoperationevent ISA __InstanceDeletionEvent then the volume was removed.

It would seem that when __instanceoperationevent ISA __InstanceModificationEvent then the volume was ejected, but it's not clear to me what other kind of operation could cause this. As the volume is still connected at this point, it's probably safe to deterministically query its Size using the first synchronous query (above) to check.

asynchronous WQL queries seem to callable in two different ways, as either temporary or permanent WMI event consumers. The difference isn't huge, but permanent filters+consumers seem to be recommended and don't seem to run afoul of WQL query "quotas".

Either way, there's no sane way to handle the resulting WMI events using JavaScript callbacks passed in via js-ctypes. :-( That left looking for a way to consume the events and then communicate them back to Firefox.

I ended up using a Strawberry perl script based on DBD::WMI per @Corion's answer to a perlmonks question to poll asynchronously for events every 2 seconds and then used IO::Socket::INET report the results to Firefox by sending them over a TCP socket. (You could do this in any language at all - I happen to be comfortable with Perl).

I then implemented nsIServerSocket from within my addon, waiting for \n terminated lines to parse the collected input and do the same modelling and synthetic events as described above.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!