Тема: AHK: Как работать с областью System Tray
Всем привет! Работает ли AutoHotKey с областью System Tray?
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Всем привет! Работает ли AutoHotKey с областью System Tray?
По большому счёту работает, но нужно конкретизировать.
Нужно правой кнопкой мыши нажимать на иконку в tray.
Henior, отредактируй название темы. Слова "Trey" не существует. И, если хочешь, чтоб ответили, опиши поподробнее задачу: по какой иконке, почему нельзя вручную.
Как отредактировать название темы?
Нужно автоматизировать скрипт, для этого нужно, чтобы при запуске скрипта, в области системного трея, скрипт нажимал правой кнопкой на иконку и выбирал, в раскрывшемся меню, пункт. Например настройки.
Название темы можно изменить, отредактировав первое сообщение.
На какую конкретно иконку? На свою, или на первую попавшуюся?
Воспользуйтесь командой MouseClick. Если местоположение иконки изменяется, его можно определить при помощи команды ImageSearch.
На свою!
Приведите пожалуйста пример использования ImageSearch.
Написал небольшой скриптик, но при запуске выдает ошибку
CoordMode Pixel, Screen
ImageSerch, FoundX, FoundY, 0, 0, A_ScreenWidth, A_ScreenHeight, *75 D:\img_test\icon.jpg
if ErrorLevel = 0
{
MsgBox %FoundX%, FoundY
Sleep, 100
}
else
{
MsgBox find not icon
}
Ошибка
icon.jpg
Подскажите, что не так?
Эта тема поближе будет: http://www.forum.script-coding.com/view … 847#p47847
Если не принципиально AHK, то здесь готовый пример на Autoit http://www.forum.script-coding.com/view … 847#p47847 (№5, "left" в предпоследней строке заменить на "right")
Эта тема поближе будет: http://www.forum.script-coding.com/view … 847#p47847
Сообразно ей, эмуляция клика правой кнопкой по иконке указанного приложения в трее (в данном случае по иконке ICQ):
#NoTrayIcon
SetBatchLines, -1
App = ICQ
PROCESS_VM_OPERATION := (0x8)
PROCESS_VM_READ := (0x10)
PROCESS_QUERY_INFORMATION := (0x400)
SizeOfTBBUTTON := 20, SizeOfTRAYDATA := 24
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
PAGE_READWRITE := 0x4
WM_USER := 0x400
TB_BUTTONCOUNT := (WM_USER + 24)
TB_GETBUTTON := (WM_USER + 23)
WM_RBUTTONDOWN := 0x204
WM_RBUTTONUP := 0x205
hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32 ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
hChild := DllCall("FindWindowEx", UInt, A_Index = 1 ? hShell_TrayWnd : hChild
, UInt, 0, Str, A_LoopField, UInt, 0)
; последнее вложенное — искомое окно — ToolbarWindow32 делаем последним найденным
WinWait, ahk_id %hChild%
WinGet, PID, PID
hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ, UInt, 0, UInt, PID)
lpData := DllCall("VirtualAllocEx", UInt, hProcess, UInt, 0
, UInt, SizeOfTBBUTTON
, UInt, MEM_COMMIT
, UInt, PAGE_READWRITE)
DetectHiddenWindows, On
VarSetCapacity(TBBUTTON, SizeOfTBBUTTON)
VarSetCapacity(TRAYDATA, SizeOfTRAYDATA)
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
SendMessage, TB_GETBUTTON, A_Index - 1, lpData
DllCall("ReadProcessMemory", UInt, hProcess, UInt, lpData
, UInt, &TBBUTTON
, UInt, SizeOfTBBUTTON, UInt, 0)
DllCall("ReadProcessMemory", UInt, hProcess, UInt, NumGet(TBBUTTON, 12)
, UInt, &TRAYDATA
, UInt, SizeOfTRAYDATA, UInt, 0)
hWnd := NumGet(TRAYDATA)
WinGet, ProcessName, ProcessName, ahk_id %hWnd%
if ProcessName not contains %App%
Continue
uID := NumGet(TRAYDATA, 4)
nMsg := NumGet(TRAYDATA, 8)
Break
}
DllCall("VirtualFreeEx", UInt, hProcess , UInt, lpData, UInt, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", UInt, hProcess)
if (uID = "")
MsgBox, Иконки указанного приложения не найдено!
else
{
PostMessage, nMsg, uID, WM_RBUTTONDOWN,, ahk_id %hWnd%
PostMessage, nMsg, uID, WM_RBUTTONUP,, ahk_id %hWnd%
}
Меню появится вблизи курсора.
Отредактировал, исправил ошибку: отсчёт иконок начинался с индекса 1 (нужно было с 0), и первая иконка не учитывалась.
А можно сей замечательный скрипт переделать под Win x64?
Можно, конечно, сделать поиск по цвету пикселя, а потом посылать правый клик.
Но хоть убейте не могу понять почему такой код на икспи иногда посылает двойной клик,
а на семерке вообще ничего не посылает?
ControlClick, ToolBarWindow321, ahk_class Shell_TrayWnd, , right
А можно сей замечательный скрипт переделать под Win x64?
Можно, посмотрю вечером.
Отлично!
И хотелось бы получить ответ на второй вопрос.
Но хоть убейте не могу понять почему такой код на икспи иногда посылает двойной клик,
а на семерке вообще ничего не посылает?ControlClick, ToolBarWindow321, ahk_class Shell_TrayWnd, , right
Не знаю, а что должно происходить? Куда конкретно посылается клик, ведь не указано.
А можно сей замечательный скрипт переделать под Win x64?
Вот под любую битность (протестировано на скайпе, аська на семёрке у меня пока не установлена):
#NoTrayIcon
WM_RBUTTONDOWN := 0x204, WM_RBUTTONUP := 0x205
PostMessageToTrayIcon("Skype.exe", WM_RBUTTONDOWN, WM_RBUTTONUP)
PostMessageToTrayIcon(ExeFileName, Messages*)
{
/*
Секретная структура TRAYDATA :)
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
PROCESS_VM_OPERATION := 0x8
PROCESS_VM_READ := 0x10
PROCESS_QUERY_INFORMATION := 0x400
SizeOfTBBUTTON := 8 + A_PtrSize*3
SizeOfTRAYDATA := 16 + A_PtrSize*2
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
PAGE_READWRITE := 0x4
WM_USER := 0x400
TB_BUTTONCOUNT := WM_USER + 24
TB_GETBUTTON := WM_USER + 23
hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32 ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
hChild := DllCall("FindWindowEx", Ptr, A_Index = 1 ? hShell_TrayWnd : hChild
, UInt, 0, Str, A_LoopField, UInt, 0, Ptr)
; последнее вложенное — искомое окно — ToolbarWindow32 делаем последним найденным
WinWait, ahk_id %hChild%
WinGet, PID, PID
hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ, UInt, 0, UInt, PID, Ptr)
lpData := DllCall("VirtualAllocEx", Ptr, hProcess, UInt, 0
, UInt, SizeOfTBBUTTON
, UInt, MEM_COMMIT
, UInt, PAGE_READWRITE, Ptr)
DetectHiddenWindows, On
VarSetCapacity(TBBUTTON, SizeOfTBBUTTON)
VarSetCapacity(TRAYDATA, SizeOfTRAYDATA)
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
SendMessage, TB_GETBUTTON, A_Index - 1, lpData
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, lpData
, Ptr, &TBBUTTON
, UInt, SizeOfTBBUTTON, UInt, 0)
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, NumGet(TBBUTTON, 8 + A_PtrSize)
, Ptr, &TRAYDATA
, UInt, SizeOfTRAYDATA, UInt, 0)
hWnd := NumGet(TRAYDATA)
WinGet, ProcessName, ProcessName, ahk_id %hWnd%
if (ProcessName != ExeFileName)
Continue
uID := NumGet(TRAYDATA, A_PtrSize)
nMsg := NumGet(TRAYDATA, A_PtrSize + 4)
Break
}
DllCall("VirtualFreeEx", Ptr, hProcess, Ptr, lpData, UInt, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", Ptr, hProcess)
if (uID = "")
MsgBox, Иконки указанного приложения не найдено!
else
for key, value in Messages
{
PostMessage, nMsg, uID, value,, ahk_id %hWnd%
Sleep, 50
}
}
Для посыла кликов иконкам ahk-скриптов такой вариант не годится, exe-файл у них один и тот же, здесь нужно на хэндл главного окна скрипта ориентироваться.
О, спасибо!
Не знаю, а что должно происходить? Куда конкретно посылается клик, ведь не указано.
Как это не указывается?
Клик посылается в середину контрола ToolBarWindow321 окна ahk_class Shell_TrayWnd
А где сказано, что именно в середину? Я не нашёл.
В Options.
Xn: Specify for n the X position to click at, relative to the control's upper left corner. If unspecified, the click will occur at the horizontal-center of the control.
Yn: Specify for n the Y position to click at, relative to the control's upper left corner. If unspecified, the click will occur at the vertical-center of the control.
http://www.autohotkey.com/docs/commands … lClick.htm
А скрипт не работает.
Ни одну иконку не может найти.
Странно что у Вас это работает на x64, т.к. у
ReadProcessMemory типы параметров следующие: Ptr, Ptr, Ptr, Ptr, Ptr
FindWindowEx: Ptr, Ptr, String(Ptr), String(Ptr)
VirtualAllocEx: Ptr, Ptr, Ptr, Int, Int
VirtualFreeEx: Ptr, Ptr, Ptr, Int
Someone, если в функции указатель на переменную со строкой, можно вместо Ptr, &Var указать Str, Var. Если вместо хэндла используется 0, вполне подойдет и UInt.
А скрипт не работает.
Malcev, приведи код, как он выглядит у тебя.
А скрипт не работает.
Скрипт работает. Клики по иконке приложения происходят если иконка видима.
Говорит, что
Иконки указанного приложения не найдено!
Иконка видима.
#NoTrayIcon
WM_RBUTTONDOWN := 0x204, WM_RBUTTONUP := 0x205
PostMessageToTrayIcon("rgsender_gui.exe", WM_RBUTTONDOWN, WM_RBUTTONUP)
PostMessageToTrayIcon(ExeFileName, Messages*)
{
/*
Секретная структура TRAYDATA :)
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
PROCESS_VM_OPERATION := 0x8
PROCESS_VM_READ := 0x10
PROCESS_QUERY_INFORMATION := 0x400
SizeOfTBBUTTON := 8 + A_PtrSize*3
SizeOfTRAYDATA := 16 + A_PtrSize*2
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
PAGE_READWRITE := 0x4
WM_USER := 0x400
TB_BUTTONCOUNT := WM_USER + 24
TB_GETBUTTON := WM_USER + 23
hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32 ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
hChild := DllCall("FindWindowEx", Ptr, A_Index = 1 ? hShell_TrayWnd : hChild
, UInt, 0, Str, A_LoopField, UInt, 0, Ptr)
; последнее вложенное — искомое окно — ToolbarWindow32 делаем последним найденным
WinWait, ahk_id %hChild%
WinGet, PID, PID
hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ, UInt, 0, UInt, PID, Ptr)
lpData := DllCall("VirtualAllocEx", Ptr, hProcess, UInt, 0
, UInt, SizeOfTBBUTTON
, UInt, MEM_COMMIT
, UInt, PAGE_READWRITE, Ptr)
DetectHiddenWindows, On
VarSetCapacity(TBBUTTON, SizeOfTBBUTTON)
VarSetCapacity(TRAYDATA, SizeOfTRAYDATA)
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
SendMessage, TB_GETBUTTON, A_Index - 1, lpData
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, lpData
, Ptr, &TBBUTTON
, UInt, SizeOfTBBUTTON, UInt, 0)
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, NumGet(TBBUTTON, 8 + A_PtrSize)
, Ptr, &TRAYDATA
, UInt, SizeOfTRAYDATA, UInt, 0)
hWnd := NumGet(TRAYDATA)
WinGet, ProcessName, ProcessName, ahk_id %hWnd%
if (ProcessName != ExeFileName)
Continue
uID := NumGet(TRAYDATA, A_PtrSize)
nMsg := NumGet(TRAYDATA, A_PtrSize + 4)
Break
}
DllCall("VirtualFreeEx", Ptr, hProcess, Ptr, lpData, UInt, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", Ptr, hProcess)
if (uID = "")
MsgBox, Иконки указанного приложения не найдено!
else
for key, value in Messages
{
PostMessage, nMsg, uID, value,, ahk_id %hWnd%
Sleep, 50
}
}
Для начала проверь, работает ли с иконкой скайпа.
Если вместо хэндла используется 0, вполне подойдет и UInt.
Кто Вам сказал этот бред? И вообще там у Вас не везде тип корректно указан даже когда параметр не равен 0.
Скайпа нету.
Но msseces.exe не находит.
Microsoft Security Essentials.
Кто Вам сказал этот бред?
Ну, во-первых опыт (никогда не было с этим проблем), во-вторых, можно рассудить логически. Зачем в DllCall указывается тип данных? Чтобы было понятно, каков их размер в битах. А какой размер 0?
И вообще там у Вас не везде тип корректно указан даже когда параметр не равен 0.
А где конкретно?
Скайпа нету.
Странно, я вижу тебя в скайпе.
Но msseces.exe не находит.
Ну не знаю. Скрипт предусматривает, что у приложения есть связанное с иконкой скрытое окно. Может, те, что у тебя, устроены как-то по-другому.
А какой размер 0?
Размер значения "0" если оно является указателем зависит от архитектуры, под которую скомпилировано приложение: 4 или 8 байт для 32 и 64 битных приложений соотвественно.
А где конкретно?
Например в 3 местах
UInt, SizeOfTBBUTTON
т.к. размер типа SIZE_T зависит от архитектуры.
Странно, я вижу тебя в скайпе.
У меня он на XP установлен.
Смотри, как можно сделать.
Вот программка, которая висит в трее (устанавливать не надо).
http://nosleephd.codeplex.com/
Так вот я только что проверил - На XP клик происходит, а на семерке нет (не может найти иконку).
во-вторых, можно рассудить логически. Зачем в DllCall указывается тип данных? Чтобы было понятно, каков их размер в битах. А какой размер 0?
Ну логически-то как раз ошибка очевидна. Пусть нулевой хендл передаётся в первом параметре на x64 как 4-байтовое число. Тогда если в результате прошлых вычислений в регистре RCX, регистр ECX оказался обнулён, а старшее двойное слово нет, то его можно не обнулять и отправлять на вход функции.
Но на практике сложно встретить ситуацию, когда такие недочёты приведут к некорректной передаче аргумента.
Пусть нулевой хендл передаётся в первом параметре на x64 как 4-байтовое число. Тогда если в результате прошлых вычислений в регистре RCX, регистр ECX оказался обнулён, а старшее двойное слово нет, то его можно не обнулять и отправлять на вход функции.
Но если указан тип UInt, то старшее слово просто не прочитается, вроде?
Malcev, такой вариант попробуй:
#NoTrayIcon
WM_RBUTTONDOWN := 0x204, WM_RBUTTONUP := 0x205
PostMessageToTrayIcon("NoSleepHDv2.0.exe", WM_RBUTTONDOWN, WM_RBUTTONUP)
PostMessageToTrayIcon(ExeFileName, Messages*)
{
/*
Секретная структура TRAYDATA :)
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
PROCESS_VM_OPERATION := 0x8
PROCESS_VM_READ := 0x10
PROCESS_QUERY_INFORMATION := 0x400
SizeOfTBBUTTON := 8 + A_PtrSize*3
SizeOfTRAYDATA := 16 + A_PtrSize*2
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
PAGE_READWRITE := 0x4
WM_USER := 0x400
TB_BUTTONCOUNT := WM_USER + 24
TB_GETBUTTON := WM_USER + 23
hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32 ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
hChild := DllCall("FindWindowEx", Ptr, A_Index = 1 ? hShell_TrayWnd : hChild
, Ptr, 0, Str, A_LoopField, UInt, 0, Ptr)
; последнее вложенное — искомое окно — ToolbarWindow32 делаем последним найденным
WinWait, ahk_id %hChild%
WinGet, PID, PID
hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ, UInt, 0, UInt, PID, Ptr)
lpData := DllCall("VirtualAllocEx", Ptr, hProcess, UInt, 0
, Ptr, SizeOfTBBUTTON
, UInt, MEM_COMMIT
, UInt, PAGE_READWRITE, Ptr)
DetectHiddenWindows, On
VarSetCapacity(TBBUTTON, SizeOfTBBUTTON)
VarSetCapacity(TRAYDATA, SizeOfTRAYDATA)
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
SendMessage, TB_GETBUTTON, A_Index - 1, lpData
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, lpData
, Ptr, &TBBUTTON
, Ptr, SizeOfTBBUTTON, Ptr, 0)
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, NumGet(TBBUTTON, 8 + A_PtrSize)
, Ptr, &TRAYDATA
, Ptr, SizeOfTRAYDATA, Ptr, 0)
hWnd := NumGet(TRAYDATA)
WinGet, ProcessName, ProcessName, ahk_id %hWnd%
if (ProcessName != ExeFileName)
Continue
uID := NumGet(TRAYDATA, A_PtrSize)
nMsg := NumGet(TRAYDATA, A_PtrSize + 4)
Break
}
DllCall("VirtualFreeEx", Ptr, hProcess, Ptr, lpData, Ptr, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", Ptr, hProcess)
if (uID = "")
MsgBox, Иконки указанного приложения не найдено!
else
for key, value in Messages
{
PostMessage, nMsg, uID, value,, ahk_id %hWnd%
Sleep, 50
}
}
На семерке не находит, на XP находит.
Но если указан тип UInt, то старшее двойное слово просто не прочитается, вроде?
Не понял. На x64 всегда используется fastcall, и первый параметр всегда передаётся через RCX. А вызываемая функция ничего о типах не знает, что ей дали в регистрах и стеке, то она и использует.
Разумеется на практике AHK обнулит регистр перед передачей.
размер типа SIZE_T зависит от архитектуры.
Там пара байт всего читается, ошибка будет только если больше четырёх гигов копировать.
На семерке не находит, на XP находит.
Посмотри что функции возвращают, может процесс даже не открывается.
На семерке не находит, на XP находит.
У меня на семёрке работают оба варианта кода. Другое дело, что иконка предложенного приложения вообще не реагирует на правый клик (у меня, по-крайней мере). Она зато реагирует на двойной клик, если приложение свёрнуто в трей. Вот так у меня работает (окно появляется из трея):
#NoTrayIcon
WM_LBUTTONDBLCLK := 0x203
PostMessageToTrayIcon("NoSleepHDv2.0.exe", WM_LBUTTONDBLCLK)
PostMessageToTrayIcon(ExeFileName, Messages*)
{
/*
Секретная структура TRAYDATA :)
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
PROCESS_VM_OPERATION := 0x8
PROCESS_VM_READ := 0x10
PROCESS_QUERY_INFORMATION := 0x400
SizeOfTBBUTTON := 8 + A_PtrSize*3
SizeOfTRAYDATA := 16 + A_PtrSize*2
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
PAGE_READWRITE := 0x4
WM_USER := 0x400
TB_BUTTONCOUNT := WM_USER + 24
TB_GETBUTTON := WM_USER + 23
hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32 ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
hChild := DllCall("FindWindowEx", Ptr, A_Index = 1 ? hShell_TrayWnd : hChild
, UInt, 0, Str, A_LoopField, UInt, 0, Ptr)
; последнее вложенное — искомое окно — ToolbarWindow32 делаем последним найденным
WinWait, ahk_id %hChild%
WinGet, PID, PID
hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ, UInt, 0, UInt, PID, Ptr)
lpData := DllCall("VirtualAllocEx", Ptr, hProcess, UInt, 0
, UInt, SizeOfTBBUTTON
, UInt, MEM_COMMIT
, UInt, PAGE_READWRITE, Ptr)
DetectHiddenWindows, On
VarSetCapacity(TBBUTTON, SizeOfTBBUTTON)
VarSetCapacity(TRAYDATA, SizeOfTRAYDATA)
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
SendMessage, TB_GETBUTTON, A_Index - 1, lpData
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, lpData
, Ptr, &TBBUTTON
, UInt, SizeOfTBBUTTON, UInt, 0)
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, NumGet(TBBUTTON, 8 + A_PtrSize)
, Ptr, &TRAYDATA
, UInt, SizeOfTRAYDATA, UInt, 0)
hWnd := NumGet(TRAYDATA)
WinGet, ProcessName, ProcessName, ahk_id %hWnd%
if (ProcessName != ExeFileName)
Continue
uID := NumGet(TRAYDATA, A_PtrSize)
nMsg := NumGet(TRAYDATA, A_PtrSize + 4)
Break
}
DllCall("VirtualFreeEx", Ptr, hProcess, Ptr, lpData, UInt, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", Ptr, hProcess)
if (uID = "")
MsgBox, Иконки указанного приложения не найдено!
else
for key, value in Messages
{
PostMessage, nMsg, uID, value,, ahk_id %hWnd%
Sleep, 50
}
}
На семерке не находит
Повторюсь
Скрипт работает. Клики по иконке приложения происходят если иконка видима.
Т.е. по иконке не спрятанной в NotifyIconOverflowWindow.
То что не реагирует на правый клик - это я знаю.
Но на висте 64бит и на семерке 64 бит у меня не находит иконки - выскакивает msgbox.
Функции возвращают числа, кроме hWnd := NumGet(TRAYDATA)
msgbox % hWnd = 0
Может из-за этого?
Т.е. по иконке не спрятанной в NotifyIconOverflowWindow.
Иконки все видно.
Так у меня тоже клик не посылается.
ControlClick, ToolBarWindow321, ahk_class Shell_TrayWnd, , right
Посмотри, что возвращают обе ReadProcessMemory().
А это, что и куда вписать, чтобы посмотреть?
Вместо
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, lpData
, Ptr, &TBBUTTON
, Ptr, SizeOfTBBUTTON, Ptr, 0)
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, NumGet(TBBUTTON, 8 + A_PtrSize)
, Ptr, &TRAYDATA
, Ptr, SizeOfTRAYDATA, Ptr, 0)
напиши
MsgBox, % DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, lpData
, Ptr, &TBBUTTON
, Ptr, SizeOfTBBUTTON, Ptr, 0)
MsgBox, % DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, NumGet(TBBUTTON, 8 + A_PtrSize)
, Ptr, &TRAYDATA
, Ptr, SizeOfTRAYDATA, Ptr, 0)
1
0
1
0
1
0
и т.д.
Тогда такой код:
#NoTrayIcon
WM_LBUTTONDBLCLK := 0x203
PostMessageToTrayIcon("NoSleepHDv2.0.exe", WM_LBUTTONDBLCLK)
PostMessageToTrayIcon(ExeFileName, Messages*)
{
/*
Секретная структура TRAYDATA :)
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
PROCESS_VM_OPERATION := 0x8
PROCESS_VM_READ := 0x10
PROCESS_QUERY_INFORMATION := 0x400
SizeOfTBBUTTON := 8 + A_PtrSize*3
SizeOfTRAYDATA := 16 + A_PtrSize*2
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
PAGE_READWRITE := 0x4
WM_USER := 0x400
TB_BUTTONCOUNT := WM_USER + 24
TB_GETBUTTON := WM_USER + 23
hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32 ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
hChild := DllCall("FindWindowEx", Ptr, A_Index = 1 ? hShell_TrayWnd : hChild
, Ptr, 0, Str, A_LoopField, UInt, 0, Ptr)
; последнее вложенное — искомое окно — ToolbarWindow32 делаем последним найденным
WinWait, ahk_id %hChild%
WinGet, PID, PID
hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ, UInt, 0, UInt, PID, Ptr)
lpData := DllCall("VirtualAllocEx", Ptr, hProcess, UInt, 0
, Ptr, SizeOfTBBUTTON
, UInt, MEM_COMMIT
, UInt, PAGE_READWRITE, Ptr)
DetectHiddenWindows, On
VarSetCapacity(TBBUTTON, SizeOfTBBUTTON)
VarSetCapacity(TRAYDATA, SizeOfTRAYDATA)
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
SendMessage, TB_GETBUTTON, A_Index - 1, lpData
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, lpData
, Ptr, &TBBUTTON
, Ptr, SizeOfTBBUTTON, Ptr, 0)
if !DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, NumGet(TBBUTTON, 8 + A_PtrSize)
, Ptr, &TRAYDATA
, Ptr, SizeOfTRAYDATA, Ptr, 0)
MsgBox, % A_LastError
hWnd := NumGet(TRAYDATA)
WinGet, ProcessName, ProcessName, ahk_id %hWnd%
if (ProcessName != ExeFileName)
Continue
uID := NumGet(TRAYDATA, A_PtrSize)
nMsg := NumGet(TRAYDATA, A_PtrSize + 4)
Break
}
DllCall("VirtualFreeEx", Ptr, hProcess, Ptr, lpData, Ptr, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", Ptr, hProcess)
if (uID = "")
MsgBox, Иконки указанного приложения не найдено!
else
for key, value in Messages
{
PostMessage, nMsg, uID, value,, ahk_id %hWnd%
Sleep, 50
}
}
Какое число выводится?
299
ERROR_PARTIAL_COPY
299 (0x12B)
Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
Это к Александр_'у, наверное.
Попробуй на 32-битном экзешнике запустить.
У тебя вообще какой битности ahk?
Все понятно, у меня была установлена 32-битная AHK.
Хотя я был уверен, что 64 бита.
Н-да. Лоханул чутка.
"Если указанный процесс -64-ехбитный процесс и вызывающий процесс 32-ухбитный, функция терпит неудачу и последний код ERROR_PARTIAL_COPY".
В общем, в код нужно добавить проверку соответствия битности процессов.
Окончательный вариант такой:
#NoTrayIcon
WM_LBUTTONDBLCLK := 0x203
PostMessageToTrayIcon("Skype.exe", WM_LBUTTONDBLCLK)
PostMessageToTrayIcon(ExeFileName, Messages*)
{
/*
Секретная структура TRAYDATA :)
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
if (A_PtrSize = 4 && A_Is64bitOS)
{
MsgBox, Вы пользуетесь 32-битной версией AHK на 64-битной системе! Функция не будет работать. Запустите скрипт под AHK x64!
return
}
PROCESS_VM_OPERATION := 0x8
PROCESS_VM_READ := 0x10
PROCESS_QUERY_INFORMATION := 0x400
SizeOfTBBUTTON := 8 + A_PtrSize*3
SizeOfTRAYDATA := 16 + A_PtrSize*2
MEM_COMMIT := 0x1000
MEM_RELEASE := 0x8000
PAGE_READWRITE := 0x4
WM_USER := 0x400
TB_BUTTONCOUNT := WM_USER + 24
TB_GETBUTTON := WM_USER + 23
hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32 ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
hChild := DllCall("FindWindowEx", Ptr, A_Index = 1 ? hShell_TrayWnd : hChild
, Ptr, 0, Str, A_LoopField, UInt, 0, Ptr)
; последнее вложенное — искомое окно — ToolbarWindow32 делаем последним найденным
WinWait, ahk_id %hChild%
WinGet, PID, PID
hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ, UInt, 0, UInt, PID, Ptr)
lpData := DllCall("VirtualAllocEx", Ptr, hProcess, UInt, 0
, Ptr, SizeOfTBBUTTON
, UInt, MEM_COMMIT
, UInt, PAGE_READWRITE, Ptr)
DetectHiddenWindows, On
VarSetCapacity(TBBUTTON, SizeOfTBBUTTON)
VarSetCapacity(TRAYDATA, SizeOfTRAYDATA)
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
SendMessage, TB_GETBUTTON, A_Index - 1, lpData
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, lpData
, Ptr, &TBBUTTON
, Ptr, SizeOfTBBUTTON, Ptr, 0)
DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, NumGet(TBBUTTON, 8 + A_PtrSize)
, Ptr, &TRAYDATA
, Ptr, SizeOfTRAYDATA, Ptr, 0)
hWnd := NumGet(TRAYDATA)
WinGet, ProcessName, ProcessName, ahk_id %hWnd%
if (ProcessName != ExeFileName)
Continue
uID := NumGet(TRAYDATA, A_PtrSize, "UInt")
nMsg := NumGet(TRAYDATA, A_PtrSize + 4, "UInt")
Break
}
DllCall("VirtualFreeEx", Ptr, hProcess, Ptr, lpData, Ptr, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", Ptr, hProcess)
if (uID = "")
MsgBox, Иконки указанного приложения не найдено!
else
for key, value in Messages
{
PostMessage, nMsg, uID, value,, ahk_id %hWnd%
Sleep, 50
}
}
Added A_Is64bitOS.
Можно изменить:
if (A_PtrSize = 4 && A_Is64bitOS)
{
MsgBox, Вы пользуетесь 32-битной версией AHK на 64-битной системе! Функция не будет работать. Запустите скрипт под AHK x64!
return
}
А, точно! Отредактировал.
Да, кстати!
VirtualAllocEx: Ptr, Ptr, Ptr, Int, Int
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
В то же время DllCall:
Types of Arguments and Return Values
Int
An unsigned Int (UInt) is also used quite frequently, such as for DWORD.
Так что правильно всё же: VirtualAllocEx: Ptr, Ptr, Ptr, UInt, UInt
Так что правильно всё же: VirtualAllocEx: Ptr, Ptr, Ptr, UInt, UInt
В данном случае важна размерность параметров, а не их знаковость. Они все равно копируются как есть и от их знаковости значение, передаваемое в функцию никак не изменится.
То есть, считаешь случайным, что в пункте статьи, озаглавленном Int, специально говорится, что для DWORD используется UInt? Так и я говорил, что если для размера структур использовать UInt вместо Ptr, ничего не изменится.
Так и я говорил, что если для размера структур использовать UInt вместо Ptr, ничего не изменится.
Изменится, выше даже говорили в каком случае это произойдет.
Ну, тогда ведь и разница между UInt и Int есть. UInt или DWORD — это целое число от 0 до 0xFFFFFFFF. Int — от -0x80000000 до 0x7FFFFFFF. Т. е. для числа 0xFDCBA987 Int не подойдёт, если его указать, возникнет ошибка.
Т. е. для числа 0xFDCBA987 Int не подойдёт, если его указать, возникнет ошибка.
Нет, не возникает ошибки, и функция получает именно 0xFDCBA987. Другое дело, что если она ожидает Int, то она его интерпретирует как отрицательное число.
Someone, YMP:
DllCall("MyDll.dll\MyInc", "int", 0x80000000/2, "ptr")
Какое значение должно передаться в функцию MyInc?
Александр_
0x40000000, а в чём подвох?
Александр_
0x40000000, а в чём подвох?
В том, что на 32-битной машине 0x80000000/2 при знаковом делении даёт 0xС0000000, а при беззнаковом 0x40000000.
YMP пишет:Александр_
0x40000000, а в чём подвох?В том, что на 32-битной машине 0x80000000/2 при знаковом делении даёт 0xС0000000, а при беззнаковом 0x40000000.
А как вы определили 0x80000000 знаковое или нет? Тип указанный в DllCall а данном случае никак не влияет на результат деления.
Это все равно что:
i:=0x80000000/2
DllCall("MyDll.dll\MyInc", "int", i, "ptr")
Другое дело, что если она ожидает Int, то она его интерпретирует как отрицательное число.
А на каком этапе произойдёт эта интерпретация? При передаче числа в DllCall() или непосредственно в вызываемую API? Если только на втором, тогда какой смысл указания типов данных в DllCall()?
Если только на втором, тогда какой смысл указания типов данных в DllCall()?
Смысл в размере передаваемых данных.
Зачем в DllCall() тогда отдельно существуют Int и UInt? Можно было бы обойтись одним Int.
А на каком этапе произойдёт эта интерпретация? При передаче числа в DllCall() или непосредственно в вызываемую API? Если только на втором, тогда какой смысл указания типов данных в DllCall()?
Уже сама API-функция будет интерпретировать число как знаковое или беззнаковое.
Зачем различные типы целых чисел, не совсем понятно. Если бы при выходе значения за пределы указанного типа это как-то сигнализировалось, например, в ErrorLevel, тогда понятно бы было. Но в ErrorLevel ноль. Поведение AutoHotkey в случае выхода за пределы типа разное для разных типов. Например, если послать "Char, 0x6600000", то и придёт в функцию 0x6600000, что уже явно не Char. Но если выйти за пределы Int64, то в этом случае передаётся максимально поддерживаемое значение, т.е. -0x8000000000000000 или 0x7FFFFFFFFFFFFFFF соответственно.
Как сказано в справке, типы имеют значение при передаче указателей на числа, т.е. "Char*", "Int*" и т.п. После вызова функции эти переменные обновляются, на случай, если функция их изменила. Числа там хранятся в виде строк. Чтобы правильно перевести записанное функцией число в строковый вид, нужно знать тип этого числа. В случае Char* значение 0xFF будет переведено в строку как "-1", а в случае UChar* как "255".
В возвращаемых значениях типы играют такую же роль, там тоже нужно знать, как правильно перевести число в строковое представление.
Вообще да, справка говорит, что
Prepend the letter U to any of the integer types above to interpret it as an unsigned integer (UInt64, UInt, UShort, and UChar). Strictly speaking, this is necessary only for return values and asterisk variables because it does not matter whether an argument passed by value is unsigned or signed (except for Int64).
Кстати говоря у AHK вообще полные ягодицы в плане приведения типов:
Msgbox % DllCall(A_ScriptDir "\TestDll00.dll\PervertInc", "char", -1, "uint64")
Где PervertInc:
__declspec(dllexport) UINT64 PervertInc(DWORD x) // просто прибавляем единицу, без знака.
{
return (UINT64)x+1;
}
На выходе получаем 0x100000000(2^33). Т.е. в функцию передаётся нихрена не "char", а вполне себе "int". Отсюда следует и полная импотенция при работе со знаками.
А какой смысл передавать char в функцию, принимающую dword?
А что изменить в этом скрипте, чтобы при посылке нажатия правой кнопки мыши в окошо скайпа, меню появлялось не там где находится мышка, а там где находится иконка скайпа?
54-ый пост.
Окончательный вариант такой:
А можно ли его изменить, чтобы работало на 32-битной версии AHK на 64-битной системе?
Можно, но без гарантии. Вроде, я уже приводил примеры работы с иконками трея для любых соотношений битностей.
Завтра смогу написать.
Я только это помню, но там немного другое:
http://forum.script-coding.com/viewtopi … 430#p92430
У меня так работает:
#NoTrayIcon
WM_LBUTTONDBLCLK := 0x203
PostMessageToTrayIcon("Skype.exe", WM_LBUTTONDBLCLK)
PostMessageToTrayIcon(ExeFileName, Messages*)
{
/*
Недокументированная структура TRAYDATA
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
static WM_USER := 0x400, TB_BUTTONCOUNT := WM_USER + 24, TB_GETBUTTON := WM_USER + 23
, PtrSize := A_Is64bitOS ? 8 : 4, SizeOfTBBUTTON := 8 + PtrSize*3, SizeOfTRAYDATA := 16 + PtrSize*2
hShell_TrayWnd := WinExist("ahk_class Shell_TrayWnd")
ChildClasses = TrayNotifyWnd|SysPager|ToolbarWindow32 ; классы окон в порядке вложенности
Loop, parse, ChildClasses, |
hChild := DllCall("FindWindowEx", Ptr, A_Index = 1 ? hShell_TrayWnd : hChild
, Ptr, 0, Str, A_LoopField, UInt, 0, Ptr)
WinExist("ahk_id" hChild)
WinGet, PID, PID
if !IsObject(RemoteBuff := New RemoteBuffer(PID, SizeOfTBBUTTON))
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось создать удалённый буфер`nОшибка " A_LastError, Str, "", UInt, 0)
DHW_Prev := A_DetectHiddenWindows
DetectHiddenWindows, On
SendMessage, TB_BUTTONCOUNT
Loop % ErrorLevel {
SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr
RemoteBuff.Read(TBBUTTON, SizeOfTBBUTTON)
TraydataOffset := NumGet(&TBBUTTON + 8 + PtrSize) - RemoteBuff.ptr
RemoteBuff.Read(TRAYDATA, SizeOfTRAYDATA, TraydataOffset)
hWnd := NumGet(&TRAYDATA)
WinGet, Name, ProcessName, % "ahk_id" hWnd
if (Name != ExeFileName)
Continue
uID := NumGet(&TRAYDATA, PtrSize, "UInt")
nMsg := NumGet(&TRAYDATA, PtrSize + 4, "UInt")
Break
}
if (uID = "")
MsgBox, Иконки указанного приложения не найдено!
else
for key, value in Messages
{
PostMessage, nMsg, uID, value,, ahk_id %hWnd%
Sleep, 50
}
DetectHiddenWindows, %DHW_Prev%
}
Class RemoteBuffer
{
__New(PID, size)
{
static PROCESS_VM_OPERATION := 0x8, PROCESS_VM_WRITE := 0x20, PROCESS_VM_READ := 0x10
, MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x4
if !(this.hProc := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))
Return
if !(this.ptr := DllCall("VirtualAllocEx", Ptr, this.hProc, UInt, 0, Ptr, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
Return, "", DllCall("CloseHandle", Ptr, this.hProc)
}
__Delete()
{
DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
DllCall("CloseHandle", Ptr, this.hProc)
}
Read(ByRef LocalBuff, size, offset = 0)
{
VarSetCapacity(LocalBuff, size, 0)
if !DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, Ptr, size, Ptr, 0)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось прочитать данные`nОшибка " A_LastError, Str, "", UInt, 0)
Return 1
}
}
Для последнего кода — с какой настройкой посылать один клик?
Один клик состоит из двух сообщений.
Штука в том, как их вписать — образцов чего не нашел.
Куда вписать, в ф-ию? Образец чего?
У себя откопал взятый где-то аналогичный скрипт, куда добавил возможность писать сообщения в стиле ahk (в вашем случае "Click" или "LButton" или "LCM"):
/*
Send mouse click to tray icon. Example:
PostMessage2TrayIconProcName("processX.exe", "Click Up Right") ; "WM_LBUTTONDOWN" / "RButton" / "RCM Dn" / "Click 2"
PostMessage2TrayIconProcName("proc.exe", [0x204, 0x205]) PostMessage2TrayIconProcName("proc.exe", 0x203)
Limitation:
1) Может работать неправильно, если одновременно происходит пользовательский ввод.
Возможное решение: блокировать ввод на время выполнения.
2) На строке
CurrentProcessName := oWMI.Get("Win32_Process.Handle=" PID).Name
возникает ошибка, если в трее остались иконки прибитых программ.
WM_LBUTTONDOWN = 0x201 WM_RBUTTONDOWN = 0x204 WM_MBUTTONDOWN = 0x207
WM_LBUTTONUP = 0x202 WM_RBUTTONUP = 0x205 WM_MBUTTONUP = 0x208
WM_LBUTTONDBLCLK = 0x203 WM_RBUTTONDBLCLK = 0x206 WM_MBUTTONDBLCLK = 0x209
WM_MOUSEMOVE = 0x200 WM_MOUSEWHEEL = 0x20A WM_MOUSEHWHEEL = 0x20E
*/
PostMessage2TrayIconProcName(ProcessName, messages)
{
if (InStr(messages, "C") || InStr(messages, "B")) ; string, contain Click/LButton/LCM
{
keyDirectionN := InStr(messages, "D") ? 1 : (InStr(messages, "Up") ? 2 : (InStr(messages, "2") ? 3 : 4))
whatKeyN := InStr(messages, "R") ? 2 : InStr(messages, "M") ? 3 : 1 ; Right/Middle
MouseClickWMCodesTable := [ [[WM_LBUTTONDOWN := 0x201], [WM_LBUTTONUP := 0x202], [WM_LBUTTONDBLCLK := 0x203], [0x201, 0x202]]
, [[WM_RBUTTONDOWN := 0x204], [WM_RBUTTONUP := 0x205], [WM_RBUTTONDBLCLK := 0x206], [0x204, 0x205]]
, [[WM_MBUTTONDOWN := 0x207], [WM_MBUTTONUP := 0x208], [WM_MBUTTONDBLCLK := 0x209], [0x207, 0x208]] ]
messages := MouseClickWMCodesTable[whatKeyN, keyDirectionN]
}
static WM_USER := 0x400, TB_BUTTONCOUNT := WM_USER + 24, TB_GETBUTTON := WM_USER + 23
, PtrSize := A_Is64bitOS ? 8 : 4, SizeOfTBBUTTON := 8 + PtrSize*3, SizeOfTRAYDATA := 16 + PtrSize*2
oWMI := ComObjGet("winmgmts:")
DHW_Prev := A_DetectHiddenWindows
DetectHiddenWindows, On
Loop 2
{
ControlGet, hWnd, hwnd,, ToolbarWindow321, % "ahk_class " . (A_Index = 1 ? "Shell_TrayWnd" : "NotifyIconOverflowWindow")
WinExist("ahk_id" hWnd)
WinGet, PID, PID
if (A_Index = 1 && !IsObject(RemoteBuff := New RemoteBuffer(PID, SizeOfTRAYDATA))) {
DetectHiddenWindows, %DHW_Prev%
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось создать удалённый буфер`nОшибка " A_LastError, Str, "", UInt, 0)
}
SendMessage, TB_BUTTONCOUNT
Loop % ErrorLevel
{
SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr
if ! ( pTBBUTTON := RemoteBuff.Read(SizeOfTBBUTTON) )
|| !pTRAYDATA := RemoteBuff.Read(SizeOfTRAYDATA, NumGet(pTBBUTTON + 8 + PtrSize) - RemoteBuff.ptr) {
DetectHiddenWindows, %DHW_Prev%
Return 1
}
WinGet, PID, PID, % "ahk_id" hWnd := NumGet(pTRAYDATA+0)
CurrentProcessName := oWMI.Get("Win32_Process.Handle=" PID).Name
if (CurrentProcessName = "AutoHotkey.exe")
{
WinGetTitle, Title, % "ahk_id" hWnd
CurrentProcessName := RegExReplace(Title, "i).*\\(.*) - autohotkey v[\.\d]+", "$1")
}
if (CurrentProcessName = ProcessName)
{
uID := NumGet(pTRAYDATA + PtrSize, "UInt")
uCallbackMessage := NumGet(pTRAYDATA + PtrSize + 4, "UInt")
; BlockInput, On
; SendInput {Click Up}{Click Right Up} ; hack
messages := IsObject(messages) ? messages : [messages]
for i, message in messages
PostMessage, uCallbackMessage, uID, message,, % "ahk_id" hWnd
; BlockInput, Off
DetectHiddenWindows, %DHW_Prev%
Return 0
}
}
}
DetectHiddenWindows, %DHW_Prev%
Return 1
}
Class RemoteBuffer
{
__New(PID, size)
{
static PROCESS_VM_OPERATION := 0x8, PROCESS_VM_WRITE := 0x20, PROCESS_VM_READ := 0x10
, MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x4
if !(this.hProc := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))
Return
if !(this.ptr := DllCall("VirtualAllocEx", UInt, this.hProc, UInt, 0, UInt, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
Return, "", DllCall("CloseHandle", Ptr, this.hProc)
}
__Delete()
{
DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
DllCall("CloseHandle", Ptr, this.hProc)
}
Read(size, offset = 0)
{
static LocalBuff
VarSetCapacity(LocalBuff, size, 0)
if !DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, size, UInt, 0)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось прочитать данные`nОшибка " A_LastError, Str, "", UInt, 0)
VarSetCapacity(LocalBuff, -1)
Return &LocalBuff
}
Write(pLocalBuff, size, offset = 0)
{
res := DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
Return res ? res : 0, (!res) ? DllCall("MessageBox", Ptr, 0, Str, "Не удалось записать данные`nОшибка " A_LastError, Str, "", UInt, 0)
}
}
DD, в 77 коде идет обращение к этой функции - PostMessageToTrayIcon(ExeFileName, Messages*)
Звездочка в параметре функции означает, что передается несколько аргументов.
В данной функции они потом извлекаются тут:
for key, value in Messages
{
PostMessage, nMsg, uID, value,, ahk_id %hWnd%
Sleep, 50
}
Следовательно, чтобы послать одиночное нажатие вам надо написать так:
WM_LBUTTONDOWN = 0x201, WM_LBUTTONUP = 0x202
PostMessageToTrayIcon("Skype.exe", WM_LBUTTONDOWN, WM_LBUTTONUP)
Спасибо, уважаемые! Почему-то, для значка облачного клиента MEGAsync.exe, никакие клики не отрабатывали — но нужное окно выводится через Run)).
stealzy
Не получалось правильно вписать в код "WM_LBUTTONDOWN" и "WM_LBUTTONUP", потому что нигде на форуме так, как их записал выше Malcev, они не проходят)).
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться