1

Тема: AHK: Клик по иконке другой программы в трее или вызов ее меню

Клик по иконке другой программы в трее или вызов ее меню — это вообще возможно без пиксельхантинга(тем более панель задач может быть скрыта)?

2

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

Где-то уже писал, но вот подправленные варианты. По порядковому индексу иконки, отправляем сообщения первой иконке в трее:

#NoTrayIcon
idx := 1
PostMessage2TrayIconIndex(idx
   , "Tray"   ; если иконка в Shell_TrayWnd, пишем "Tray", если в NotifyIconOverflowWindow — ""
   , WM_RBUTTONDOWN := 0x204
   , WM_RBUTTONUP := 0x205)  ; последние параметры — сообщения которые нужно отправить
Return

PostMessage2TrayIconIndex(idx, TrayOrOverflow, 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

   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   ControlGet, hWnd, hwnd,, ToolbarWindow321, % "ahk_class " . (TrayOrOverflow = "Tray" ? "Shell_TrayWnd" : "NotifyIconOverflowWindow")
   WinExist("ahk_id" hWnd)
   WinGet, PID, PID

   if !IsObject(RemoteBuff := New RemoteBuffer(PID, SizeOfTRAYDATA)) {
      DetectHiddenWindows, %DHW_Prev%
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось создать удалённый буфер`nОшибка " A_LastError, Str, "", UInt, 0)
   }
 
   SendMessage, TB_GETBUTTON, idx - 1, RemoteBuff.ptr
   if ! ( pTBBUTTON := RemoteBuff.Read(SizeOfTBBUTTON) )
      || !pTRAYDATA := RemoteBuff.Read(SizeOfTRAYDATA, NumGet(pTBBUTTON + 8 + PtrSize) - RemoteBuff.ptr) {
      DetectHiddenWindows, %DHW_Prev%
      Return
   }

   WinExist("ahk_id" NumGet(pTRAYDATA+0))
   uID := NumGet(pTRAYDATA + PtrSize, "UInt")
   uCallbackMessage := NumGet(pTRAYDATA + PtrSize + 4, "UInt")

   for i, message in messages
      PostMessage, uCallbackMessage, uID, message
   
   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", 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)
   }
}

По названию процесса (или если ahk, то по имени скрипта), отправляем сообщения иконке Skype.exe:

#NoTrayIcon
PostMessage2TrayIconProcName("skype.exe", WM_RBUTTONDOWN := 0x204, WM_RBUTTONUP := 0x205)
Return

PostMessage2TrayIconProcName(ProcessName, 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
   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
         }

         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")

            for i, message in messages
               PostMessage, uCallbackMessage, uID, message,, % "ahk_id" hWnd
            DetectHiddenWindows, %DHW_Prev%
            Return
         }
      }
   }
   DetectHiddenWindows, %DHW_Prev%
   MsgBox, % "Иконка процесса " . ProcessName . " не найдена"
}

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)
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

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

(this.hProc := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))

Я в основном учился по справке.
Вы не подскажете что проштудировать, чтобы самому составлять такие выражения?

4

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

Не совсем понял, вопрос про конструкцию this.hProc, или про winapi-функцию?

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

5

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

И то, и другое наверно. Если кинете пару ссылок как с этим обращатся с примерами, буду балгодарен.

6

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

Ключевое слово "this" используется при работе с классами, но изучить следует всю статью Объекты.
Справочная информация о winapi-функциях (и иногда примеры использования) находится поиском в MSDN, например OpenProcess.

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

7 (изменено: becauseim, 2015-09-01 16:50:01)

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

teadrinker пишет:

отправляем сообщения иконке Skype.exe

http://puu.sh/jWbRJ/decc068137.png

Была бы кстати рабочая версия. Поделитесь, пожалуйста.
Имеется в виду пкм по заданной программе в трее.

8

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

Чем поделиться? У меня последний скрипт работает, у остальных, вроде, тоже работал. Какая ОС у вас, какая версия AHK?

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

9

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

Win10 x64
v1.1.22.02

10

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

Битность AHK тоже имеет значение.

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

11

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

Не знаю, как это можно узнать. В окне Help указано именно так.

12

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

Что за окно Help и именно как там указано?

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

13

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

teadrinker пишет:

как там указано?

Так как я указал. Где указывается битность, я не знаю, к сожалению.
http://puu.sh/jWjRu/16ebcca739.png

14

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

А, понял, в справке этого не может быть написано, она общая. Откройте папку, куда установлен AHK, найдите файл AutoHotkey.exe, наведите на него курсор. Должно появиться всплывающее окно типа такого:

https://cloclo20.cloud.mail.ru/weblink/thumb/xw1/3xWFwYtFNHBh/2015.09.01-18.27.33.7.jpg

Там будет описание файла.

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

15

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

64

16

Re: AHK: Клик по иконке другой программы в трее или вызов ее меню

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

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