1

Тема: AHK: Взаимодействие с диалогами, созданными DllCall

Рассмотрим пример по включению настройки «Отображать содержимое окна при перетаскивании» подделкой действий пользователя с апплетом Панели управления.
(Это нужно лишь для примера, саму задачу можно решить с помощью

DllCall("SystemParametersInfo"

без всяких мелькающих окон):

Run % "rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,2",,, PID
WinWait Свойства: Экран ahk_pid %PID%
WinGet HWND, ID
ControlClick &Эффекты..., ahk_id %HWND%

WinWait Эффекты
Control Check,, &Отображать содержимое окна при перетаскивании
ControlSend ,, {Enter}

WinWait ahk_id %HWND%
ControlClick ThemePreview1
ControlSend ,, {Enter}

Но ведь вместо rundll32.exe можно вызвать функцию из DLL собственными средствами AHK: раз уж наш сценарий начал выполняться, значит они доступны, а присутствует или нет rundll32.exe в точности не известно. Тем более, что мы выбрали функцию, вызываемую с помощью rundll32.exe лишь для примера. Если при этом вызвать функцию из DLL в отдельном процессе (например AHK-сценарий перезапускает себя с каким-либо ключом), то всё работает так же. Но опять же, если рассматривать общий случай, файл сценария может быть удалён во время его работы, поэтому хотелось бы обойтись одним процессом.

Если заменить первые две строки:

;Run % "rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,2",,, PID
;WinWait Свойства: Экран ahk_pid %PID%
DllCall("shell32.dll\Control_RunDLL" . (A_IsUnicode? "W": "A")
	, "UInt", A_ScriptHwnd ; HWND hwnd // 0 не работает...
	, "Ptr", 0 ; HINSTANCE hInstance
	, "Str", "desk.cpl,,2" ; LPTSTR lpszCmd
	, "UInt", 1) ; nCmdShow
Process Exist
WinWait Свойства: Экран ahk_pid %ErrorLevel%
WinGet HWND, ID
ControlClick &Эффекты..., ahk_id %HWND%

WinWait Эффекты
Control Check,, &Отображать содержимое окна при перетаскивании
ControlSend ,, {Enter}

WinWait ahk_id %HWND%
ControlClick ThemePreview1
ControlSend ,, {Enter}

то переход к следующему действию после DllCall произойдёт только, когда созданное им окно будет закрыто сторонними средствами (например, вручную).

В cправке сказано:

Timers are useful because they run asynchronously, meaning that they will run at the specified frequency (interval) even when the script is waiting for a window, displaying a dialog, or busy with another task

Попробуем действия после DllCall, запустить в отдельном потоке с помощью таймера:

;Run % "rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,2",,, PID
;WinWait Свойства: Экран ahk_pid %PID%
SetTimer Step2, -1
DllCall("shell32.dll\Control_RunDLL" . (A_IsUnicode? "W": "A")
	, "UInt", A_ScriptHwnd ; HWND hwnd // 0 не работает...
	, "Ptr", 0 ; HINSTANCE hInstance
	, "Str", "desk.cpl,,2" ; LPTSTR lpszCmd
	, "UInt", 1) ; nCmdShow
Exit
Step2:
Process Exist
WinWait Свойства: Экран ahk_pid %ErrorLevel%
WinGet HWND, ID
ControlClick &Эффекты..., ahk_id %HWND%

WinWait Эффекты
Control Check,, &Отображать содержимое окна при перетаскивании
ControlSend ,, {Enter}

WinWait ahk_id %HWND%
ControlClick ThemePreview1
ControlSend ,, {Enter}

— в этом случае кнопка «Эффекты» нажимается, поддиалог «Эффекты» открывается и на этом всё. Если его закрыть вручную, то основной диалог уже вручную не закрывается — надо завершать сам сценарий. Ещё можно заметить, что если после  ControlClick вставить MsgBox, то до него дело дойдёт только после закрытия «Эффекты».

Что делать?

2 (изменено: stealzy, 2017-08-10 19:57:55)

Re: AHK: Взаимодействие с диалогами, созданными DllCall

Все таки ahk однопоточен, и "асинхронность" работает только? внутри языка.
Ваш пример несправедлив - таймер вызывается раньше DllCall, лучше наоборот засуньте DllCall в таймер.
Ах, да, на Win7 вызывается окно персонализации, контрола Элементы там нет.

файл сценария может быть удалён

Можно на ходу запустить бесфайловый в pipe.

3

Re: AHK: Взаимодействие с диалогами, созданными DllCall

wisgest пишет:

то переход к следующему действию после DllCall произойдёт только, когда созданное им окно будет закрыто сторонними средствами (например, вручную)

У меня ни на семёрке, ни на десятке такого не происходит, и там, и там открывается окно «Персонализация» и код выполняется дальше. Вы на XP? Пример не очень удачный.

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

4 (изменено: wisgest, 2017-08-10 20:56:33)

Re: AHK: Взаимодействие с диалогами, созданными DllCall

stealzy пишет:

Ах, да, на Win7 вызывается окно персонализации, контрола Элементы там нет.

См. присоединённый архив.

stealzy пишет:

Можно на ходу запустить бесфайловый в pipe.

Не пойдёт, если сценарий скомпилирован в EXE. В этом случае он, конечно, не может быть удалён во время работы, но придётся учитывать большее число случаев — громоздко.

stealzy пишет:

Ваш пример несправедлив - таймер вызывается раньше DllCall, лучше наоборот засуньте DllCall в таймер.

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

teadrinker пишет:

Вы на XP? Пример не очень удачный.

Да. Почему?

teadrinker пишет:

и код выполняется дальше.

Т.е. MsgBox срабатывает до закрытия диалога?!

DllCall("shell32.dll\Control_RunDLL" . (A_IsUnicode? "W": "A")
	, "UInt", A_ScriptHwnd ; HWND hwnd // 0 не работает...
	, "Ptr", 0 ; HINSTANCE hInstance
	, "Str", "desk.cpl,,2" ; LPTSTR lpszCmd
	, "UInt", 1) ; nCmdShow
MsgBox
Post's attachments

dlgs.zip 13.64 kb, 2 downloads since 2017-08-10 

You don't have the permssions to download the attachments of this post.

5

Re: AHK: Взаимодействие с диалогами, созданными DllCall

wisgest пишет:

Не пойдёт, если сценарий скомпилирован в EXE.

Понятно, что вам не подойдет, но в ahk_H это возможно.

6

Re: AHK: Взаимодействие с диалогами, созданными DllCall

wisgest пишет:

Почему?

На семёрке и десятке таких окон нет, а те, что открываются, не являются диалогами. Поэтому протестировать пример нет возможности.

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

7

Re: AHK: Взаимодействие с диалогами, созданными DllCall

wisgest пишет:

Т.е. MsgBox срабатывает до закрытия диалога?!

Да, но как я написал выше, открывающееся окно не является диалогом.

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

8 (изменено: wisgest, 2017-08-10 21:10:58)

Re: AHK: Взаимодействие с диалогами, созданными DllCall

teadrinker, а MmSys.cpl?
________________
Название вопроса не совсем удачно, т.к. подобные случаи возможны и без использования DllCall. Например открываем диалог свойств ярлыка и пытаемся взаимодействовать с ним дальше, открываем поддиалог выбора значка и т.д.

9

Re: AHK: Взаимодействие с диалогами, созданными DllCall

Да, открывается диалоговое окно «Звук».

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

10

Re: AHK: Взаимодействие с диалогами, созданными DllCall

wisgest пишет:

Например открываем диалог свойств ярлыка и пытаемся взаимодействовать с ним дальше, открываем поддиалог выбора значка и т.д.

Не совсем понятен смысл задачи. Диалоговые окна нужны для взаимодействия с пользователем, а не для эмуляции его действий.
Можно поэкспериментировать с таким таймером (он более живучий), но вряд ли это хороший путь.

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

11

Re: AHK: Взаимодействие с диалогами, созданными DllCall

teadrinker пишет:

Да, открывается диалоговое окно «Звук».

Ну хотя бы так:

;Run % "rundll32.exe MmSys.cpl,ShowFullControlPanel",,, PID
; /*
SetTimer Step2, -1
DllCall("MmSys.cpl\ShowFullControlPanel"
;	, UInt, A_ScriptHwnd ; HWND hwnd
	, UInt, 0 ; HWND hwnd
	, Ptr, 0 ; HINSTANCE hInstance
	, Ptr, 0 ; LPTSTR lpszCmd
	, UInt, 1) ; nCmdShow
Exit
Step2:
Process Exist
PID = %ErrorLevel%
; */
WinWait Свойства: Звуки и аудиоустройства ahk_pid %PID%
WinGet HWND, ID
ControlClick Гром&кость динамиков..., ahk_id %HWND%

WinWait Динамики ahk_pid %PID%
Control Check,, П&ередвигать все регуляторы одновременно

— флажок уже не устанавливается.

teadrinker пишет:

Диалоговые окна нужны для взаимодействия с пользователем, а не для эмуляции его действий.

А AutoHotkey нужен для автоматизации, в том числе путём эмуляции действий пользователя.

12 (изменено: teadrinker, 2017-08-10 22:12:50)

Re: AHK: Взаимодействие с диалогами, созданными DllCall

wisgest пишет:
DllCall("MmSys.cpl\ShowFullControlPanel"
;   , UInt, A_ScriptHwnd ; HWND hwnd
   , UInt, 0 ; HWND hwnd
   , Ptr, 0 ; HINSTANCE hInstance
   , Ptr, 0 ; LPTSTR lpszCmd
   , UInt, 1) ; nCmdShow

Так вообще ничего не происходит. На семёрке нет параметра ShowFullControlPanel.

wisgest пишет:

А AutoHotkey нужен для автоматизации, в том числе путём эмуляции действий пользователя.

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

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

13

Re: AHK: Взаимодействие с диалогами, созданными DllCall

teadrinker пишет:

Так вообще ничего не происходит.

А так?

DllCall("shell32.dll\Control_RunDLL" . (A_IsUnicode? "W": "A")
	, UInt, A_ScriptHwnd ; HWND hwnd
;	, UInt, 0 ; HWND hwnd
	, Ptr, 0 ; HINSTANCE hInstance
	, Str, "MmSys.cpl" ; LPTSTR lpszCmd
	, UInt, 1) ; nCmdShow
teadrinker пишет:

Так это самый примитивный способ автоматизации, обычно его стараются избегать

Кто бы спорил, но часто лучше как-нибудь, чем никак.

14

Re: AHK: Взаимодействие с диалогами, созданными DllCall

Так открывается такое окно:

http://i.imgur.com/a2TIQXh.png

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

15

Re: AHK: Взаимодействие с диалогами, созданными DllCall

Это на семёрке, а на десятке ничего.

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

16

Re: AHK: Взаимодействие с диалогами, созданными DllCall

На семёрке пока не закроешь окно код далее не выполняется, наверное вопрос в этом...
То есть то что надо "по нажимать" не получается.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

17

Re: AHK: Взаимодействие с диалогами, созданными DllCall

serzh82saratov, в десятку!

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

18 (изменено: serzh82saratov, 2017-08-11 00:40:57)

Re: AHK: Взаимодействие с диалогами, созданными DllCall

Ок, если так?


DllCall("SetTimer", Ptr, A_ScriptHwnd, Ptr, 1, UInt, 300, Ptr, RegisterCallback("MyTimer", "Fast"))
DllCall("shell32.dll\Control_RunDLL" . (A_IsUnicode? "W": "A")
	, UInt, A_ScriptHwnd ; HWND hwnd
;	, UInt, 0 ; HWND hwnd
	, Ptr, 0 ; HINSTANCE hInstance
	, Str, "MmSys.cpl" ; LPTSTR lpszCmd
	, UInt, 1) ; nCmdShow

MyTimer()  {
	DllCall("KillTimer", Ptr, A_ScriptHwnd, Ptr, 1)
	WinWait Звук ahk_class #32770
	Loop	
		MsgBox, , , % A_Index, 0.2
}

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

19

Re: AHK: Взаимодействие с диалогами, созданными DllCall

serzh82saratov, непосредственно следующий за командой создающей диалог код не выполняется, естественно. Но если «понажимать» запустить в другом (псевдо)потоке, то, может быть что-то и получится. Оно и получается, но только до места, где создаётся следующий диалог. Я подозреваю, хотя и не проверял, что если перед этим местом  установить следующий таймер, то чего-то и можно добиться, но как-то это некрасиво выглядит. Может быть поиграться с приоритетами или какими-то директивами, но я в этом не разбираюсь.

20

Re: AHK: Взаимодействие с диалогами, созданными DllCall

wisgest пишет:

основной диалог уже вручную не закрывается

Эту проблему я пропустил, тоже не закрывается.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

21 (изменено: wisgest, 2017-08-11 00:52:25)

Re: AHK: Взаимодействие с диалогами, созданными DllCall

serzh82saratov пишет:

Ок, если так?

Так работает, если в моём случае изменить «Звук» на «Свойства: Звуки и аудиоустройства», но оно работает и через

SetTimer MyTimer, -1

Отличий не заметил.

22

Re: AHK: Взаимодействие с диалогами, созданными DllCall

Вот так у меня срабатывает на семёрке вызов диалога «Язык и региональные стандарты» и по кнопке поддиалога «Настройка формата»:

#Persistent
DllCall("SetTimer", Ptr, A_ScriptHwnd, Ptr, id := 1, UInt, 300, Ptr, RegisterCallback("MyTimer", "F"))
Return

MyTimer()  {
   static step := 0
   if (++step = 1)  {
      DllCall("shell32.dll\Control_RunDLL" . (A_IsUnicode ? "W" : "A")
         , "UInt", A_ScriptHwnd, "Ptr", 0, "Str", "intl.cpl", "UInt", nCmdShow := 1)
   }
   else if (step = 2)  {
      WinWait, Язык и региональные стандарты
      ControlClick, &Дополнительные параметры...
   }
   else if (step = 3)  {
      WinWait, Настройка формата
      ControlClick, Button3  ; Button OK, по OK не срабатывает
   }
   else if (step = 4)  {
      DllCall("KillTimer", Ptr, A_ScriptHwnd, Ptr, id := 1)
      WinWait, Язык и региональные стандарты
      ControlClick, Button4  ; Button OK
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

23

Re: AHK: Взаимодействие с диалогами, созданными DllCall

"UInt", A_ScriptHwnd?

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

24

Re: AHK: Взаимодействие с диалогами, созданными DllCall

А, это я же с коллеги wisgest скопировал. Конечно Ptr.

teadrinker пишет:

Вот так у меня срабатывает на семёрке вызов диалога «Язык и региональные стандарты»

Хотя как раз в этом случае весь сыр-бор ни к чему, поскольку можно просто

Run intl.cpl

без привязки к окну диалога.

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

25

Re: AHK: Взаимодействие с диалогами, созданными DllCall

teadrinker пишет:

Хотя как раз в этом случае весь сыр-бор ни к чему, поскольку можно просто

Run intl.cpl

— это открытие *.cpl сопоставленным приложением, т.е. rundll32.exe…

Думаю, это решение можно воспроизвести и встроенной командой SetTimer:

wisgest пишет:

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

Т.е. почему требуется разрыв между (step = 1) и (step = 2) понятно, а между (step = 2) и (step = 3) и почему они не могут быть в одном «потоке» — уже не очень…