WM_DEVICECHANGE и все все все

Обложился USB-кардридерами, сую в них карточки и высовываю и чувствую, что схожу с ума.

Вот есть сообщение WM_DEVICECHANGE, оно прилетает

  1. когда я вставляю USB-флешку (не карту)
  2. когда я подключаю ридер (без карты)
  3. когда я подключаю ридер с заранее вставленной карточкой.

А вот если подключить ридер без карты (прилетит сообщение), а потом вставить карточку - на вставление карточки WM_DEVICECHANGE не прилетает.

Kaspersky Antivirus со мной солидарен, свое "обнаружен съемный диск" он показывает в случаях 1 и 3 (ну а второй - фильтрует, потому что устройство есть, но не ready), а если сначала подключить ридер, а потом сунуть карту - проверить ее не предлагают.

При этом сидюк (ну точнее Daemon Tools, где я в 2015-м году возьму сидюк) ведет себя нормально - на монтирование/размонтирование диска сообщения есть.

Windows Explorer и Adobe Bridge при этом сувание-вынимание карточки отрабатывают отлично, чуют.

ВОПРОСЫ МОИ

  1. ЧЯДНТ?
  2. Есть какие-то более здравые идеи, чем поллинг по списку removable drives раз в пару секунд с проверкой

То есть гугление показало, что я не первый, кто об эти грабли ударился, рекомендуют вот подписываться на обновления про USB-устройства (вот и еще вот), только вот радости это не принесло, второй пример - уверенно показывает подключение кардридера, но на вставление карточки в ридер никак не реагирует, а на какие GUID надо подписаться для вставления карты - я не понимаю, мне бы слова списать.

UPDATE (переношу историю из комментариев)

  • В USB нет уведомлений "о вставке карты", поэтому поллинг - единственный вариант.
  • Вот насколько мне кажется, этим поллингом занимается сама Windows, раз секунд в 6 (10 раз в минуту), во всяком случае устройство появляется в Explorer с задержкой до 8 секунд и вряд-ли все общения с ним (прочитать метку диска и т.п) занимают более двух.
  • Поллинг GetVolumeInformation (по известной букве диска) раз в секунду - перестает возвращать ошибку ("нет диска") с такой же задержкой, что и устройство появляется в Explorer.
  • Соответственно, есть основания думать, что поллингом Windows (как минимум, семерка) - занимается централизованно ("в ядре").
  • Поллинг - разумное, получается, поведение. Естественно, надо делать так:
    • Продолжать получать нотификации о появлении/удалении букв диска
    • Поллить только те, про которые известно что они Removable (или ничего неизвестно - буква появилась, но никакой файловой системы там никогда не было, поэтому узнать нельзя).
  • Вопрос, тем не менее, остается: если система централизованно поллит (?? уверенности нет, но если бы поллили юзерские программы независимо, то моя, с поллингом раз в секунду, получала бы информацию о диске за пару секунд, а не за 7-8 как и Explorer/Autoplay), то какого хрена WM_DEVICECHANGE не прилетает.

Comments

если я правильно сошёл с ума, всё ты верно понял.

"да, мы о***ли"(c), и так оно всё и есть.

А конструктив то где? Поллинг раз в пару секунд?

Ну, да, всё так и есть.

Интересно, кстати, подсмотреть, как это у MacOS X сделано.

Но штука-то именно в том, что USB девайс *по собственной воле* отправить мессаж хосту не может -- ну, кроме как переинициализировать коннекшн, что непросто, дорого и чревато, IIUC.

Ну вот когда вставляю карточку - что-то куда-то отправляется же? Иначе бы диск системой не находился, а он находится.
Что мешает это форвардить дальше, в WM_DEVICECHANGE - я просто не понимаю.

В макоси - коллбеки у Disk Arbitration:
DARegisterDiskDisappearedCallback
DARegisterDiskAppearedCallback
DARegisterDiskUnmountApprovalCallback
DARegisterDiskDescriptionChangedCallback

Но до макоси я еще не добрался, не исключено что там такое же говно (с другой стороны, простой мониторинг /Volumes на изменения (через fsevents или kqueue), - решает мою проблему /помониторить вставление-вынимание флешек/ практически полностью)

Сколь я понимаю, как раз таки *не* отправляется ничего, потому что неоткуда взяться.

Вот ридер карточек, ему присвоена буква диска Q:
Я могу про него спросить GetVolumeInformation, если карточки нет - получу код ошибки (который анализирую на ERROR_NOT_READY, если она - карточки нет, если другая - считаю невалидной эту букву).

Сую карточку, больше ничего не трогаю, что происходит:
- в Disk Administrator - диск находится
- в эксплорере - появляется
- GetVolumeInformation - возвращает про эту букву приличные всякие слова (метку диска, serial number)

То есть винда как-то узнала, что карточку воткнули - и сходила почитала оттуда.

Есть, на самом деле, интерфейс про Portable Devices, пишут оттуда можно получить нотификацию, но он Vista и выше, не хочу использовать (WMI - тоже не хочу)

Ну так это и есть поллинг, то, что ты описываешь. Когда ты вызывешь GVI винда сама обращается к ридеру. А пока хост к ридеру не обратится он должен молчать, вставили там в него карту или нет.

Он не "должен молчать" -- он не имеет возможности что-либо сказать, не выдали ему ;)

Ну, он может сделать отключение-подключение

И, более того, я видел ридер с 4-мя дырками который показывал буквы дисков только при вставлении карточки. Т.е. подключаешь его — и тишина. Суьёш карту — появляется буква диска. Одна. Сушёь вторую — появляется вторая. Вынимаешь — исчезает.

Ну, да я про это выше: http://blog.lexa.ru/comment/42428#comment-42428 и писал.

Там много других граблей закопано, если я правильно всё понимаю.

Ну, сделали уродский протокол, а он и разползся, что уж теперь делать ;)

При том что что FireWire, что Thunderbolt -- объективно сильно лучше -- USB всё равно всех подебит.

FireWire в другом месте крупно прокололись. Технически. Так, кстати, по уму, кажется нигде и не исправлено.

Ты про неотключаемый DMA? Ну, это *можно* было бы поправить. Только деманду нету, уже от слова совсем.

Скорее — про то, что везде сделали его жёстко-отключаемым а надо бы по адресам устройств, что бы вот данным конкретным внешним диском можно было бы пользоваться, а хакерская железка бы обломилась.

То есть (как и пишут ниже) - винда делает поллинг?

Какого хрена результаты этого поллинга не прилетают по DEVICECHANGE?

Деелает explorer скорее всего, а он вообще не обязан быть запущен.
Хотя ядро могло бы по результатам любого поллинга рассылать, да.

это мы одновременно про одно разными словами ;)

Ну не только explorer. В device list возникает, например.

Известно (ну то есть я прочитал, а вдаваться не стал в подробности) что можно получить нужное мне через WMI и WPD

А чем тебя, кстати, так отвращает WMI? Вроде бы на фоне конкурентов довольно внятный...

Ну вот тем, что для DEVICECHANGE код уже написан (тоже не без приколов - ему нужно окно, без окна не может).
А этот - надо разбираться и писать.

Ну и кроме того: Win32_DeviceChangeEvent - Vista и выше. А у меня XP и выше.

судя по всему, поллитнг делает не ядро, а юзерлендовые программы.

FUSE они не сделали, короче ;-P

Ты думаешь, GetVolumeInformation перечитывает диск каждый раз, а не берет кэшированное (в системе)?

Не знаю.

Я бы (при отсутствии хинтов) кешировал бы не более чем на единицы секунд, иначе пытался бы дёргать physical device.

Я к тому клоню, что оно это делает "в ядре, само".

Ага. И притом применяет неестественный интелект в зависимости от того, какое устройство является родителем носителя.

Очень consistent, ога.

Короче, у меня все работает уже! (правда под семеркой, до XP еще не добрался).

А с мониторингом вставления карт - оказывается используют миллион методов, вплоть до разбора системных событий. Что говорит о том, что место - ГОВЕННОЕ.

Вот я и не буду его больше трогать. Поллинг - так поллинг.

Ну вот кстати. У меня дрочка поллинг GetVolumeInformation - раз в секунду.

При вставлении карты - оно думает где-то 7-8 секунд, появляется в эксплорере, всплывает окно автоплея и одновременно вот с автоплеем - появляется в моей программе.

То есть вот сдается мне, что там внутри централизованный поллинг, а GetVolumeInformation таки дает кэшированное.

Короче, поллинг работает. Хоть и противен мне.

Ну линукс как-то обнаруживает попадание карты в карт-ридер и тут же спрашивает, что мол делать.
Винда тоже видит это событие, но окошко мне не выдаёт (картридер, правда, встроенный в ноут). FAR вон буковку добавляет.
FAR, кстати, как реагирует на это? Если нормально- может заглянуть в код?

Far, да, хорошая идея.
Пошел читать.

У Far нету этой проблемы. Там если буква диска есть, на нее можно пойти (ну и получить ошибку, что нету ничего).

Соответственно, там просто WM_DEVICECHANGE, которой достаточно вполне для обновления списка буковок.

Я тоже изучал этот вопрос, но несколько иначе. Во-первых, ситуация сильно разная для PCI-кардридеров и кардридеров, подключенных по USB. Для PCI аппаратные уведомления ходят. Для USB, как известно, нет и я запускал WinXP внутри VirtualBox, который помаргивает своим индикатором активности USB при наличии оной и прокидывал туда USB-кардридер из хоста.

И таки XP мигает индикатором USB постоянно, пока в неё кардридер прокинут, независимо от того, вставлена в него карточка или нет. Примерно три раза в 2 секунды. И при вставлении карточки Explorer реагирует на неё с этой самой задержкой поллинга.

Оппа! А в каких устройствах ты встречал PCI кардридеры? Все, что попадались мне -- на внутренних USB хабах.

я видел в старых ноутах Sony Vaio. TI'шный чип прямо на PCI с поддержкой SD и MS.

Вообще, SDHC-спецификация прописывает хост-интерфейс и чипов, которые умеют её прямо на PCI есть. Можно посмотреть, например, что поддерживает FreeBSD -CURRENT :))))

Осталось найти это в жывой природе, ога.

;-P

Ну на чём-то авторы отлаживались :)
Как я понимаю, в ноутах по прежнему бывает.

В ноуте у меня стареньком.