1 (изменено: Drugoy, 2013-10-20 02:09:04)

Тема: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Конкретно интересует:
1. Можно ли как-то с помощью OnMessage() отслеживать подключение и отключение дисков к компьютеру (скажем, если пользователь подсоединил/вытащил флэшку)?
Если нет, то как иначе наиболее изящным образом можно отследить подключение и отключение дисков к компьютеру?

Можно, конечно, втупую по кругу выполнять DriveGet,,list и сравнивать текущий результат с прошлым, но это не комильфо.

2

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

http://forum.script-coding.com/viewtopic.php?id=875

Забыл пароль и потерял e-mail.

3

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Можно получить букву подключаемого/отключаемого диска:

OnMessage(0x219, "WM_DEVICECHANGE")
return

WM_DEVICECHANGE(wp, lp)
{
   static DBT_DEVICEARRIVAL := 0x8000, DBT_DEVICEREMOVECOMPLETE := 0x8004, DBT_DEVTYP_VOLUME := 2
   
   if ((wp = DBT_DEVICEARRIVAL || wp = DBT_DEVICEREMOVECOMPLETE) && NumGet(lp+4, "UInt") = DBT_DEVTYP_VOLUME)
   {
      dbcv_unitmask := NumGet(lp+12, "UInt")
   
      Loop 26
         Letter := Chr(Asc("A") + A_Index - 1)
      until (dbcv_unitmask >> (A_Index - 1))&1
   
      ToolTip % "Диск """ Letter ":"" " (wp = DBT_DEVICEARRIVAL ? "подключен" : "отключен")
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

4

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Спасибо за ответы, прошу прощения, что не воспользовался поиском более тщательно, перед тем как создавать тему.

Тогда ещё вопрос про OnMessage() - а может быть можно с его помощью также отслеживать появление новых и умирание старых процессов? Это бы сильно оптимизировало работу моего ScriptManager'а.

5

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

http://forum.script-coding.com/rules.html#3.11.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

6

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Drugoy пишет:

Что можно отследить с помощью OnMessage()?

Нет, так не пойдёт. Верни прежнее название, и создай новую тему, если нужно.

Заголовок темы необходимо составить так, чтобы он как можно точнее отражал суть темы.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7 (изменено: Drugoy, 2013-10-21 16:32:03)

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker пишет:

Можно получить букву подключаемого/отключаемого диска:

Воспользовался Вашим кодом встроив его в свой скрипт, но полезли ошибки:

---------------------------
MasterScript.ahk
---------------------------
Error:  0x8001010D - Не удается выполнить исходящий вызов, так как приложение обрабатывает входящий синхронный вызов.


    Line#
    493: scriptsOldSnapshot := []
    494: Else
    495: scriptsOldSnapshot := scriptsSnapshot
    496: processesSnapshot := []
    496: scriptsSnapshot := []
    496: indexScripts := 0
    496: indexProcesses := 0
--->    497: For Process, in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
    498: {
    499: indexProcesses += 1
    500: processesSnapshot[indexProcesses, "pid"] := Process.ProcessId  
    501: processesSnapshot[indexProcesses, "exe"] := Process.ExecutablePath  
    503: if (RegExMatch(Process.CommandLine, "Si)^(""|\s)*\Q" A_AhkPath "\E.*\\(?<Name>.*\.ahk)(""|\s)*$", script)) && (RegExMatch(Process.CommandLine, "Si)^(""|\s)*\Q" A_AhkPath "\E.*""(?<Path>.*\.ahk)(""|\s)*$", script))  
    504: {
    505: indexScripts += 1

Continue running the script?
---------------------------
Да   Нет   
---------------------------

Как понятно из процитированного в ошибке кода из моего скрипта - я использую ComObjGet для получения списка запущенных процессов, что и стало причиной конфликта с предложенным тобой OnMessage(0x219, "WM_DEVICECHANGE").

Я про синхронность/асинхронность вызовов мало чего знаю (ведь, я не настоящий сварщик), скажите пожалуйста: как избавиться от подобных ошибок?
Т. к. OnMessage() ловит входящие вызовы, то такой вызов всегда может попасться на момент, когда в скрипте ещё выполняется исходящий вызов ComObjGet, что неминуемо приведёт к процитированной выше ошибке.
Единственным выходом, который мне видится возможным (но очень нежелательным) - это запустить этот OnMessage() в отдельном скрипте, к которому периодически обращаться (исходящими вызовами) из основного скрипта и опрашивать его на наличие новых событий.
Есть ли вариант лучше?

8

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

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

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker,

SetTimer, ProcessList, 1000

OnMessage(0x219, "WM_DEVICECHANGE")
return

WM_DEVICECHANGE(wp, lp)
{
    Static DBT_DEVICEARRIVAL := 0x8000, DBT_DEVICEREMOVECOMPLETE := 0x8004, DBT_DEVTYP_VOLUME := 2
    If ((wp = DBT_DEVICEARRIVAL || wp = DBT_DEVICEREMOVECOMPLETE) && NumGet(lp + 4, "UInt") = DBT_DEVTYP_VOLUME)
    {
        dbcv_unitmask := NumGet(lp+12, "UInt")
        Loop, 26    ; The number of letters in latin alphabet.
        {
            Letter := Chr(Asc("A") + A_Index - 1)
        } Until (dbcv_unitmask >> (A_Index - 1))&1
        MsgBox, % "Диск """ Letter ":"" " (wp = DBT_DEVICEARRIVAL ? "подключен" : "отключен")
    }
}

ProcessList:
    For Process In ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
        indexProcesses++
Return

10

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Ага, посмотрю завтра.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

11

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker
В принципе, мне это интересно не из спортивного или теоретического интереса, а из вполне практического: мне это нужно для работы моего masterscript'а.

Я тут попробовал и оказывается, что твой код для отслеживания изменений в списке процессов - работает бесконфликтно с этим OnMessage(), предложенным тобой в этой теме.

Т.е. я могу этот проблемный For Process In ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process") исполнять однократно на старте, а дальше за изменениями в списке процессов следить уже тем кодом.

Я с COM-объектами не знаком, потому прошу совета, описал всё в том топике.

12

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Только не нужно использовать ComObjGet("winmgmts:") в скрипте дважды, достаточно один раз получить этот объект, сохранить его в переменную и работать всё время с ней.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

13

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker, спасибо за замечание.

14

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker пишет:

Можно получить букву подключаемого/отключаемого диска:

OnMessage(0x219, "WM_DEVICECHANGE")
return

WM_DEVICECHANGE(wp, lp)
{
   static DBT_DEVICEARRIVAL := 0x8000, DBT_DEVICEREMOVECOMPLETE := 0x8004, DBT_DEVTYP_VOLUME := 2
   
   if ((wp = DBT_DEVICEARRIVAL || wp = DBT_DEVICEREMOVECOMPLETE) && NumGet(lp+4, "UInt") = DBT_DEVTYP_VOLUME)
   {
      dbcv_unitmask := NumGet(lp+12, "UInt")
   
      Loop 26
         Letter := Chr(Asc("A") + A_Index - 1)
      until (dbcv_unitmask >> (A_Index - 1))&1
   
      ToolTip % "Диск """ Letter ":"" " (wp = DBT_DEVICEARRIVAL ? "подключен" : "отключен")
   }
}

а можно ли как-то получить объём диска? столкнулся с проблемой, что если телефон подключить по USB к компьютеру, то он отображается как диск в моём компьютере, но до тех пор, пока в телефоне не нажать "turn on USB storage" - объём диска 0 байт и его нельзя открыть. А мне надо как-то разграничить состояния, когда подключён диск без доступа к чтению и диск с таким доступом.

15

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Если именно объём, то

DriveGet, Capacity, Capacity, C:\
MsgBox, % Capacity

В мегабайтах.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

16

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

спасибо, чего-то я и забыл про эту команду.

17 (изменено: serzh82saratov, 2014-05-29 11:22:40)

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Воспользовался кодом, надо бы обновить в коллекции.
Кстати из любопытства, на WMI возможны решения?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

18

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Дополнил, на WMI возможно.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

19

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Ещё так можно:

OnMessage(0x219, "WM_DEVICECHANGE")
return

EventHandling(drive, event)
{
   TrayTip, Диск %drive%:, %event%,, 1
}

WM_DEVICECHANGE(wp, lp)
{
   static DBT_DEVICEARRIVAL := 0x8000, DBT_DEVICEREMOVECOMPLETE := 0x8004, DBT_DEVTYP_VOLUME := 2
   
   if ((wp = DBT_DEVICEARRIVAL || wp = DBT_DEVICEREMOVECOMPLETE) && NumGet(lp+4, "UInt") = DBT_DEVTYP_VOLUME)
   {
      dbcv_unitmask := NumGet(lp+12, "UInt")
      Letter := Chr(Asc("A") + ln(dbcv_unitmask)/ln(2))
      
      EventHandling(Letter, wp = DBT_DEVICEARRIVAL ? "подключен" : "отключен")
   }
}

Математику вспомнил .

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

20

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Статья интересная, спасибо.
А натуральный логарифм это не математика, это уже колдовство

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

21

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Никакого колдовства, можно и десятичный подставить. Там число dbcv_unitmask — это двойка в степени, соответствующей порядковому номеру буквы. Нам нужно узнать эту степень. Можно последовательным побитовым сдвигом (что наверняка быстрее), можно так.

MsgBox, % ln(2**20)/ln(2)
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

22

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Да уж, просто

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

23 (изменено: Drugoy, 2014-10-07 10:41:54)

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

А почему при однократном подключении+отключении флешки генерируется так много одинаковых onmessage'ей? 8 при отключении и 16-18 при подключении.
Можно ли как-то (возможно, по каким-то смежным событиям) добиться того, чтобы однократное подключение и однократное отключение генерировали только 1 событие?

24

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Что вы называете onmessag'ами? У меня при подключении флешки функция WM_DEVICECHANGE() сигнализирует один раз, при отключении — тоже один.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

25 (изменено: Drugoy, 2014-10-10 15:52:09)

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker, а как вы определили, что один? не по messagebox'у ли? если так, то это ни о чём не говорит, т.к. messagebox паузит выполнение скрипта.
Я выполнял "outputdebug, a drive (dis)appeared!" и смотрел в debugview сколько же я таких сообщений получу; оказалось, что получаю их много.

26

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Само сообщение WM_DEVICECHANGE может приходить несколько раз с разными параметрами. Но нам-то не нужно отлавливать все эти сообщения, а только с нужными описанными в функции параметрами:

if ((wp = DBT_DEVICEARRIVAL || wp = DBT_DEVICEREMOVECOMPLETE) && NumGet(lp+4, "UInt") = DBT_DEVTYP_VOLUME)
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

27

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Чего-то странно я как-то тестировал. Похоже, я outputdebug ставил после этого условия, а не внутри него.
Всё в порядке, разобрался, спасибо.

28

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Edit: оказалось, что ничего не в порядке: у меня ваш код в отдельном скрипте работает с однократным срабатыванием, а вот этот же самый код, но вставленный в мой скрипт - почему-то после выполнения процитированного if снова возвращается к нему же :-/
Если не трудно, то, кто-нибудь, пожалуйста, гляньте мой огромный и пока недоделанный скрипт. Не понимаю в чём может быть дело :-/
в нём строка 100

OnMessage(0x219, "WM_DEVICECHANGE")

и строки 1059-1081 описывают функцию

WM_DEVICECHANGE(wp, lp){…}

на строке 1079 идёт OutputDebug, который у меня срабатывает всегда дважды.

29

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Drugoy пишет:

вот этот же самый код, но вставленный в мой скрипт - почему-то после выполнения процитированного if снова возвращается к нему же

Это я не совсем понял. Но явная ошибка — помещать обработку события в ту же функцию, что его отлавливает. Обработка занимает время, в которое могут происходить новые события, и тут могут возникать сбои. В функции не должно быть ничего, кроме отлова события, а обработку лучше всего повесить на таймер.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

30 (изменено: Drugoy, 2014-10-13 20:57:39)

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker пишет:
Drugoy пишет:

вот этот же самый код, но вставленный в мой скрипт - почему-то после выполнения процитированного if снова возвращается к нему же

Это я не совсем понял.

Однократное подключение флешки (как и однократное её отключение) генерирует 2 записи в дебаг-лог, т.е. функция срабатывает дважды (уже с учётом условия If wp = 0x8000 || wp = 0x8004) на одно событие.

teadrinker пишет:

Но явная ошибка — помещать обработку события в ту же функцию, что его отлавливает. Обработка занимает время, в которое могут происходить новые события, и тут могут возникать сбои. В функции не должно быть ничего, кроме отлова события, а обработку лучше всего повесить на таймер.

Я так и не разобрался с псевдо-многопоточностью в AHK. Я пробовал выносить обработку в отдельную функцию (не по таймеру) - работает так же.
Ну добавил бы я таймер - как скрипт бы повёл себя в случае, скажем, такой колизии: с разницей в долю секунды идёт сначала подключение, а потом отключение флешки.
Возможны 2 варианта: таймер сработал между этими событиями; таймер сработал после обоих.
Что в этих случаях сделает скрипт?

31

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Drugoy пишет:

Однократное подключение флешки (как и однократное её отключение) генерирует 2 записи в дебаг-лог

Просто попробуйте для начала встатвить в программу функцию в том виде, как в примере, без всяких дебагов и обработок, и добавьте по условию Soundbeep. Так проще всего отследить, сколько раз она будет сигналить.

Drugoy пишет:

Возможны 2 варианта: таймер сработал между этими событиями; таймер сработал после обоих.
Что в этих случаях сделает скрипт?

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

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

32

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker пишет:

Просто попробуйте для начала встатвить в программу функцию в том виде, как в примере, без всяких дебагов и обработок, и добавьте по условию Soundbeep. Так проще всего отследить, сколько раз она будет сигналить.

OutputDebug и/или listlines нагляднее. Срабатывает дважды.

teadrinker пишет:

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

У меня там ещё есть следилка за появлением/смертью процессов

oSvc := ComObjGet("winmgmts:")
ComObjConnect(createSink := ComObjCreate("WbemScripting.SWbemSink"), "ProcessCreate_")
ComObjConnect(deleteSink := ComObjCreate("WbemScripting.SWbemSink"), "ProcessDelete_")
Command := "Within 1 Where TargetInstance ISA 'Win32_Process'"
oSvc.ExecNotificationQueryAsync(createSink, "select * from __InstanceCreationEvent " Command)
oSvc.ExecNotificationQueryAsync(deleteSink, "select * from __InstanceDeletionEvent " Command)

как timer будет работать ещё и параллельно с этим? возможны ли коллизии?

33

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Drugoy пишет:

Срабатывает дважды.

Добавьте в параметры:

WM_DEVICECHANGE(wp, lp, msg, hwnd)

И измените условие:

if (hwnd = A_ScriptHwnd && (wp = DBT_DEVICEARRIVAL || wp = DBT_DEVICEREMOVECOMPLETE)
   && NumGet(lp+4, "UInt") = DBT_DEVTYP_VOLUME)
Drugoy пишет:

как timer будет работать ещё и параллельно с этим? возможны ли коллизии?

Если, опять же, обработку событий ставить на таймер, всё должно быть в порядке.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

34 (изменено: Drugoy, 2014-10-15 16:21:32)

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

teadrinker, спасибо, теперь всё работает как надо. А объясните, пожалуйста, что делает проверка hwnd = A_ScriptHwnd? wm_devicechange без этой проверки ловил что ли и сообщения "направленные" другим hwnd кроме hwnd скрипта? я бы ещё понял, если бы сообщения отправлялись другим процессам, но ведь разница реально в том, что в коде самого скрипта: если в коде моего скрипта закомментировать большинство остальных строк - то удвоенные сообщения вновь превращаются в однократные, всё становится как надо.
Кстати, а почему вы предложили такой порядок аргументов для WM_DEVICECHANGE()? У майкрософта указан другой.

35

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Drugoy пишет:

А объясните, пожалуйста, что делает проверка hwnd = A_ScriptHwnd?

Сообщение WM_DEVICECHANGE рассылается всем окнам. В вашем скрипте их два: одно главное (скрытое), другое — которое вы создаёте. Отсюда и по два сигнала на каждое событие. Проверкой мы отсекаем все окна, кроме главного.

Drugoy пишет:

Кстати, а почему вы предложили такой порядок аргументов для WM_DEVICECHANGE()?

Это порядок аргументов не WM_DEVICECHANGE, а OnMessage().

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

36

Re: AHK: Можно ли узнать о подкл./откл. дисках с помощью OnMessage()?

Спасибо, теперь всё стало окончательно ясно и всё встало на свои места.