1 (изменено: BasyAlex, 2011-04-25 19:24:46)

Тема: AHK: Работа с треем

Всем привет!

Вопрос 1
При некорректном завершении программ, частенько в трее остаются их иконки (к примеру Alcohol120%). Как заставиить трей обновить своё содержимое?

Пробовал поискать какое сообщение должно ему передаваться при наведении курсора мыши на иконку неработающей проги для её исчезновения в трее через WInspector, но так и не нашел.
Кстати, бывает и обратная ситуация - при крахе Explorer-а половина иконок просто исчезает из трея и приходиться перезапускать некоторые приложения дабы они там проявились.:mad:

Вопрос 2 (Следeт из первого)
Как получить список работающих прог висящих у меня в трее? Надобность возникла из-за того, что прога создаёт тьму окон одинакового класса (без имён и какого-либа текста) и только одно из них отвечает за клики в трее.

Стоит прога WallPaper Calendar v3.0.2 build 86 от zepsoft-a для смены обоев на рабочем столе выбираем через трей "Change Wallpaper Image" и меняем обои.
В скрипте это выглядит так - перебираем из полутора десятка одинаковых окон "ahk_class TPUtilWindow" выбираем необходимое (метотом тупого перебора через цикл) и посылаем ему PostMessage:

Process,Exist,WallCal3.exe
MyProgPID:=ErrorLevel
MyVar:=2
WinGet,ClassIDVar,List,ahk_class TPUtilWindow,,
While (MyVar>0)
{
    MyProgID:=ClassIDVar%A_Index%
    WinGet,MyProgPIDVar,PID,ahk_id %MyProgID%,,
    if MyProgPIDVar=%MyProgPID%
    {
        OutputVar:=ClassIDVar%A_Index%
        MyVar-=1
    }
}
PostMessage,0x111,30,0,,ahk_id %OutputVar%
Солнышко в окошке.
Тупо пялюсь в ящик.
Пнуть ПК, гулять пойти...

2

Re: AHK: Работа с треем

угу гулять с девочкой!!! солныфко светит, а мы цалуемса!!!)

3

Re: AHK: Работа с треем

BasyAlex пишет:

Как заставиить трей обновить своё содержимое? Пробовал поискать какое сообщение должно ему передаваться при наведении курсора мыши на иконку неработающей проги для её исчезновения в трее через WInspector, но так и не нашел.

Попробовать сделать наподобие такого: Re: Очистка трея.

wodyanoi, что это за флуд?!

4 (изменено: BasyAlex, 2011-04-26 03:44:03)

Re: AHK: Работа с треем

alexii пишет:

Попробовать сделать наподобие такого: Re: Очистка трея.

Попробовал использовать wm_mousemove через PostMessage, но возникли сложности:
1
При посылании PostMessage,0x200,,,, ahk_class ToolbarWindow32 исчезает иконка неработающей проги только если она расположена крайняя-слева, а она может находиться в любом месте трея. Другими словами - у PostMessage необходимо указать координаты откуда-куда двигаться мышке. Как это сделать?

2
Возникает проблема с определением ahk_class ToolbarWindow32 - их там несколько этого типа окон (все принадлежат explorer.exe). Поэтому приходиться использовать ahk_id и смотреть его через WInspector, что не годится, конечно же.

Солнышко в окошке.
Тупо пялюсь в ящик.
Пнуть ПК, гулять пойти...

5

Re: AHK: Работа с треем

Вот так можно попробовать, хотя способ довольно кривой:

WinWait, ahk_class Shell_TrayWnd
ControlGetPos,,, W, H, ToolbarWindow321
Loop % W
   PostMessage, WM_MOUSEMOVE := 0x200,, (A_Index - 1)|((H/2)<<16), ToolbarWindow321
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

6

Re: AHK: Работа с треем

Вот так можно попробовать, хотя способ довольно кривой

Помогает, но  DrWeb выдаёт свой TrayTip прямо у курсора мыши.

Солнышко в окошке.
Тупо пялюсь в ящик.
Пнуть ПК, гулять пойти...

7

Re: AHK: Работа с треем

У меня та же проблема. Я и говорю, кривой способ. Насколько я вижу, Google ничего другого не предлагает.

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

8

Re: AHK: Работа с треем

Пошатался по форумам и пришла идея попробовать использовать TB_-сообщения. Вот толко я не нашел их hex-кодов для подстановки в SendMessage/PostMessage

Солнышко в окошке.
Тупо пялюсь в ящик.
Пнуть ПК, гулять пойти...

9

Re: AHK: Работа с треем

Скрипт для определения констант.

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

10

Re: AHK: Работа с треем

А обязательно AHK? На Autoit эти вопросы решаются без проблем

11

Re: AHK: Работа с треем

WUT пишет:

А обязательно AHK? На Autoit эти вопросы решаются без проблем

А можно ссылочку...

Солнышко в окошке.
Тупо пялюсь в ящик.
Пнуть ПК, гулять пойти...

12

Re: AHK: Работа с треем

BasyAlex пишет:

А можно ссылочку...

Сейчас размещу в соответствующем разделе оба кода

13 (изменено: WUT, 2011-04-26 21:54:56)

Re: AHK: Работа с треем

http://www.forum.script-coding.com/view … 849#p47849

14

Re: AHK: Работа с треем

WUT, спасибо! Возможно, на этой основе можно будет сделать перевод и на AHK (послушаем коллег).

15

Re: AHK: Работа с треем

Различную информацию об иконках системного трея можно получить, отправляя им сообщение TB_GETBUTTON, и считывая данные из структуры TBBUTTON. (Чтобы считать данные из удалённого процесса (explorer.exe), нужно выделить буфер в его адресном пространстве, считать данные в него, а затем скопировать их в буфер из адресного пространства вызывающего процесса.) В составе этой структуры есть член dwData, описанный в MSDN как "application-defined value". Порыскав по просторам интернета, я, наконец, нашёл (pdf) его более подробное описание:

The dwData member of the TBBUTTON structure gives us a pointer to the TRAYDATA structure for the button.

public struct TRAYDATA
{
public IntPtr hwnd;
public uint uID;
public uint uCallbackMessage;
private uint Reserved;
private uint Reserved2;
public IntPtr hIcon;
}

Возвращаясь к поставленной задаче — удалить "зависшие" иконки убитых приложений и обновить трей — можно получить хэндл родительского окна иконки (первый член структуры TRAYDATA) и проверить, существует ли его процесс (вариант с проверкой существования окна почему-то не срабатывает), затем удалить ненужную иконку, отправив ей TB_DELETEBUTTON. После этого нужно обновить трей с помощью WM_SETTINGCHANGE, иначе в области уведомлений останется пустое место.

#NoTrayIcon
SetBatchLines, -1

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_WININICHANGE := 0x1A
TB_DELETEBUTTON := (WM_USER + 22)
WM_SETTINGCHANGE := WM_WININICHANGE

; нам нужно найти хэндл окна класса ToolbarWindow32, которое является дочерним окна
; с классом SysPager, которое является дочерним окна с классом TrayNotifyWnd, которое,
; в свою очередь, является дочерним окна с классом Shell_TrayWnd (панели задач)
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)
VarSetCapacity(FilePath, A_IsUnicode ? 600 : 300)
Index = 0
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
   SendMessage, TB_GETBUTTON, Index, 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)

   WinGet, PID, PID, % "ahk_id " NumGet(TRAYDATA)
   if !PID
      SendMessage, TB_DELETEBUTTON, Index--  ; в случае удаления индексы уменьшаются на 1
   Index++
}

if (Index < IconCount)
   SendMessage, WM_SETTINGCHANGE,,,, ahk_class Shell_TrayWnd  ; иначе останется пустое место

DllCall("VirtualFreeEx", UInt, hProcess , UInt, lpData, UInt, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", UInt, hProcess)

(Чёрт, подсветку доделать никак руки не доходят!)
И напоследок, код определяющий исполнимые файлы процессов, создавших иконки в трее (нужно учитывать, что часть иконок скрыта).

#NoTrayIcon
SetBatchLines, -1

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_WININICHANGE := 0x1A
TB_DELETEBUTTON := (WM_USER + 22)
WM_SETTINGCHANGE := WM_WININICHANGE

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)
VarSetCapacity(FilePath, A_IsUnicode ? 600 : 300)
Index := 0
SendMessage, TB_BUTTONCOUNT
Loop % IconCount := ErrorLevel
{
   SendMessage, TB_GETBUTTON, Index, 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)

   WinGet, PID, PID, % "ahk_id " NumGet(TRAYDATA)
   if !PID
      SendMessage, TB_DELETEBUTTON, Index--  ; в случае удаления индексы уменьшаются на 1
   Else
   {
      hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION, UInt, 0, UInt, PID)
      if !DllCall("GetProcessImageFileName" . (A_IsUnicode ? "W" : "A")
                                                , UInt, hProc
                                                , Str, FilePath, UInt, 300)
         DllCall("Psapi\GetProcessImageFileName" . (A_IsUnicode ? "W" : "A")
                                                   , UInt, hProc
                                                   , Str, FilePath, UInt, 300)
      FilePaths .= FilePath . "`n"
      DllCall("CloseHandle", UInt, hProc)
   }
   Index++
}

if (Index < IconCount)
   SendMessage, WM_SETTINGCHANGE,,,, ahk_class Shell_TrayWnd

DllCall("VirtualFreeEx", UInt, hProcess , UInt, lpData, UInt, 0, UInt, MEM_RELEASE)
DllCall("CloseHandle", UInt, hProcess)

MsgBox, % SubStr(FilePaths, 1, -1)

Оба варианта кода рассчитаны на 32-разрядную версию Windows.

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