1

Тема: AHK: Очистить трей от иконок закрытых приложений

тс пишет:

к тому же после этого остаётся иконка — придётся обновлять трей.

Кстати ищу способ как обновить трей для очищения иконок закрытых приложений.



Перенесено из темы AHK: Ищу надёжный способ "нормально" завершать любой процесс.
ypppu

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

2

Re: AHK: Очистить трей от иконок закрытых приложений

Есть способ, довольно сложный, попозже напишу.

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

3

Re: AHK: Очистить трей от иконок закрытых приложений

попозже напишу.

Отлично, спасибо.
---
В виде изврата конечно , и не на все случаи:

 
1:: 
ControlGet, id, Hwnd, , ToolbarWindow321, ahk_class Shell_TrayWnd ahk_exe explorer.exe 
Loop 2
{
    ControlGetPos, , , CtrlW, , , ahk_id %id%
    Loop % CtrlW
        PostMessage, 0x200, 0, ((1<<16)^A_Index), , ahk_id %id%   
}
return
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

4

Re: AHK: Очистить трей от иконок закрытых приложений

С этим конечно ничего неподелаешь.

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

5

Re: AHK: Очистить трей от иконок закрытых приложений

serzh82saratov пишет:

ищу способ как обновить трей для очищения иконок закрытых приложений.

Скрипт, удаляющий из трея и из NotifyIconOverflowWindow иконки, остающиеся после некорректного завершения процессов. Нужно пользоваться интерпретатором с битностью, соответствующей битности системы.

DeleteDummyIcons()

DeleteDummyIcons()
{
/*
Недокументированная структура 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-битной системе!`nФункция " A_ThisFunc "() не будет работать. "
      . (A_IsCompiled ? "Откомпилируйте" : "Запустите") . " скрипт под AHK x64!"
      return
   }
   
   WM_USER := 0x400
   TB_BUTTONCOUNT := WM_USER + 24
   TB_GETBUTTON := WM_USER + 23
   TB_DELETEBUTTON := WM_USER + 22
   WM_SETTINGCHANGE := 0x1A
   SizeOfTBBUTTON := 8 + A_PtrSize*3
   SizeOfTRAYDATA := 16 + A_PtrSize*2
   
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   ControlGet, hTray, hwnd,, ToolbarWindow321, ahk_class Shell_TrayWnd
   ControlGet, hOverflow, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
   WinGet, PID, PID, ahk_id %hTray%

   ; создаём буфер в адресном пространстве проводника для чтения данных
   RemoteBuff := New RemoteBuffer(PID, SizeOfTRAYDATA)
   Loop 2
   {
      hwnd := A_Index = 1 ? hTray : hOverflow
      SendMessage, TB_BUTTONCOUNT,,,, ahk_id %hwnd%
      Loop % ErrorLevel
      {
         SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr,, ahk_id %hwnd%
         ; получаем структуру TBBUTTON, в ней по смещению 8 + A_PtrSize адрес структуры TRAYDATA в адресном пространстве проводника
         pTBBUTTON := RemoteBuff.Read(SizeOfTBBUTTON)
         
         ; получаем структуру TRAYDATA, первый член её — связанное с иконкой окно
         pTRAYDATA := RemoteBuff.Read(SizeOfTRAYDATA, NumGet(pTBBUTTON+0, 8 + A_PtrSize) - RemoteBuff.ptr)
         
         ; если окна не существует (процесс не существует) — удаляем иконку
         if !WinExist("ahk_id" NumGet(pTRAYDATA+0))
         {
            SendMessage, TB_DELETEBUTTON, A_Index - 1,,, ahk_id %hwnd%
            SendMessage, WM_SETTINGCHANGE,,,, ahk_class Shell_TrayWnd
         }
      }
   }
   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
      
      this.size := size
   }
   
   __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)
      DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, size, UInt, 0)
      VarSetCapacity(LocalBuff, -1)
      Return &LocalBuff
   }
   
   Write(pLocalBuff, size, offset = 0)
   {
      return DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

6

Re: AHK: Очистить трей от иконок закрытых приложений

Круто, спасибо!

Нужно пользоваться интерпретатором с битностью, соответствующей битности системы.

А это никак не поправить?

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

7

Re: AHK: Очистить трей от иконок закрытых приложений

Нет, 32-битные приложения не могут читать память 64-битных.

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

8

Re: AHK: Очистить трей от иконок закрытых приложений

teadrinker пишет:

Нет, 32-битные приложения не могут читать память 64-битных.

Разве? Я тут как-то писал функцию поиска в памяти другого процесса, что связано со чтением, и поиск из 32-битного скрипта в 64-битном процессе работал. Единственно, что указать адрес больше 32 бит невозможно.

9

Re: AHK: Очистить трей от иконок закрытых приложений

Так ведь и поинтеры, которые считываются в функции, могут быть больше 32 бит. Во всяком случае, у меня ну 32-битном интерпретаторе работает некорректно, в подробности пока не вдавался.

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

10

Re: AHK: Очистить трей от иконок закрытых приложений

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

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

11

Re: AHK: Очистить трей от иконок закрытых приложений

Вот так, вроде, сработало:

DeleteDummyIcons()

DeleteDummyIcons()
{
/*
Недокументированная структура TRAYDATA
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
   PtrSize := A_Is64bitOS ? 8 : 4
   WM_USER := 0x400
   TB_BUTTONCOUNT := WM_USER + 24
   TB_GETBUTTON := WM_USER + 23
   TB_DELETEBUTTON := WM_USER + 22
   WM_SETTINGCHANGE := 0x1A
   SizeOfTBBUTTON := 8 + PtrSize*3
   SizeOfTRAYDATA := 16 + PtrSize*2
   
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   ControlGet, hTray, hwnd,, ToolbarWindow321, ahk_class Shell_TrayWnd
   ControlGet, hOverflow, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
   WinGet, PID, PID, ahk_id %hTray%

   ; создаём буфер в адресном пространстве проводника для чтения данных
   RemoteBuff := New RemoteBuffer(PID, SizeOfTRAYDATA)
   Loop 2
   {
      hwnd := A_Index = 1 ? hTray : hOverflow
      SendMessage, TB_BUTTONCOUNT,,,, ahk_id %hwnd%
      Loop % ErrorLevel
      {
         SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr,, ahk_id %hwnd%
         ; получаем структуру TBBUTTON, в ней по смещению 8 + PtrSize адрес структуры TRAYDATA в адресном пространстве проводника
         pTBBUTTON := RemoteBuff.Read(SizeOfTBBUTTON)
         
         ; получаем структуру TRAYDATA, первый член её — связанное с иконкой окно
         pTRAYDATA := RemoteBuff.Read(SizeOfTRAYDATA, NumGet(pTBBUTTON+0, 8 + PtrSize) - RemoteBuff.ptr)
         
         ; если окна не существует (процесс не существует) — удаляем иконку
         if !WinExist("ahk_id" NumGet(pTRAYDATA+0))
         {
            SendMessage, TB_DELETEBUTTON, A_Index - 1,,, ahk_id %hwnd%
            SendMessage, WM_SETTINGCHANGE,,,, ahk_class Shell_TrayWnd
         }
      }
   }
   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 ""
      
      this.size := size
   }
   
   __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)
      DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, size, UInt, 0)
      VarSetCapacity(LocalBuff, -1)
      Return &LocalBuff
   }
   
   Write(pLocalBuff, size, offset = 0)
   {
      return DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
   }
}

Но, как говорится, на свой страх и риск .

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

12

Re: AHK: Очистить трей от иконок закрытых приложений

Чистит не до конца. Запустите побольше таких скриптов:

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

13

Re: AHK: Очистить трей от иконок закрытых приложений

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

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

14

Re: AHK: Очистить трей от иконок закрытых приложений

serzh82saratov пишет:

Чистит не до конца.

Да, после удаления иконки индексы остальных изменяются на 1. Вот так правильно:

DeleteDummyIcons()

DeleteDummyIcons()
{
/*
Недокументированная структура TRAYDATA
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
   PtrSize := A_Is64bitOS ? 8 : 4
   WM_USER := 0x400
   TB_BUTTONCOUNT := WM_USER + 24
   TB_GETBUTTON := WM_USER + 23
   TB_DELETEBUTTON := WM_USER + 22
   WM_SETTINGCHANGE := 0x1A
   SizeOfTBBUTTON := 8 + PtrSize*3
   SizeOfTRAYDATA := 16 + PtrSize*2
   
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   ControlGet, hTray, hwnd,, ToolbarWindow321, ahk_class Shell_TrayWnd
   ControlGet, hOverflow, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
   WinGet, PID, PID, ahk_id %hTray%

   ; создаём буфер в адресном пространстве проводника для чтения данных
   RemoteBuff := New RemoteBuffer(PID, SizeOfTRAYDATA)
   Loop 2
   {
      hwnd := A_Index = 1 ? hTray : hOverflow
      SendMessage, TB_BUTTONCOUNT,,,, ahk_id %hwnd%
      i := 0
      Loop % ErrorLevel
      {
         SendMessage, TB_GETBUTTON, i, RemoteBuff.ptr,, ahk_id %hwnd%
         ; получаем структуру TBBUTTON, в ней по смещению 8 + PtrSize адрес структуры TRAYDATA в адресном пространстве проводника
         pTBBUTTON := RemoteBuff.Read(SizeOfTBBUTTON)
         
         ; получаем структуру TRAYDATA, первый член её — связанное с иконкой окно
         pTRAYDATA := RemoteBuff.Read(SizeOfTRAYDATA, NumGet(pTBBUTTON+0, 8 + PtrSize) - RemoteBuff.ptr)
         
         ; если окна не существует (процесс не существует) — удаляем иконку
         if !WinExist("ahk_id" NumGet(pTRAYDATA+0))
         {
            SendMessage, TB_DELETEBUTTON, i--,,, ahk_id %hwnd%
            SendMessage, WM_SETTINGCHANGE,,,, ahk_class Shell_TrayWnd
         }
         i++
      }
   }
   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 ""
      
      this.size := size
   }
   
   __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)
      DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, size, UInt, 0)
      VarSetCapacity(LocalBuff, -1)
      Return &LocalBuff
   }
   
   Write(pLocalBuff, size, offset = 0)
   {
      return DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
   }
}
serzh82saratov пишет:

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

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

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

15 (изменено: serzh82saratov, 2014-04-23 22:56:03)

Re: AHK: Очистить трей от иконок закрытых приложений

Чистит до конца! Удалённые иконки не в NotifyIconOverflowWindow а у часиков. Но можно перетягивать туда и обратно. Они прозрачны и некликабельны. После выхода из системы эффект пропадает. Проблема осталась.

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

16

Re: AHK: Очистить трей от иконок закрытых приложений

serzh82saratov пишет:

Проблема осталась.

Не совсем ясно, подробнее. Иконки закрытых процессов нормально удаляет? Какая проблема осталась?

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

17

Re: AHK: Очистить трей от иконок закрытых приложений

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

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

18

Re: AHK: Очистить трей от иконок закрытых приложений

Попробуй перезагрузиться и позапускать скрипт на 64-битном интерпретаторе. Проблема появляется?

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

19

Re: AHK: Очистить трей от иконок закрытых приложений

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

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

20

Re: AHK: Очистить трей от иконок закрытых приложений

после перезагрузки системы?

Не системы. Запустили DeleteDummyIcons(), иконка осталась, раньше сразу исчезала. Но теперь после DeleteDummyIcons() и после перезапуска скрипта (чья иконка) она уже не становится видна.

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

21

Re: AHK: Очистить трей от иконок закрытых приложений

А если http://forum.script-coding.com/viewtopi … 206#p82206?

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

22

Re: AHK: Очистить трей от иконок закрытых приложений

Попробуй перезагрузиться и позапускать скрипт на 64-битном интерпретаторе.

Так ведь Я же о том и рассказываю.

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

23

Re: AHK: Очистить трей от иконок закрытых приложений

Это только под 32 бита.

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

24 (изменено: serzh82saratov, 2014-05-28 17:59:30)

Re: AHK: Очистить трей от иконок закрытых приложений

Ещё сократил, сделать и для х64, и в коллекцию, чтоб не потерялось.


1:: NoTrayOrphans() 

NoTrayOrphans()
{  
    For k, v In TrayIcons("ahk_class Shell_TrayWnd", "ToolbarWindow32" . GetTrayBar())  
        RemoveTrayIcon(v[1], v[2])  
    For k, v In TrayIcons("ahk_class NotifyIconOverflowWindow", "ToolbarWindow321")
        RemoveTrayIcon(v[1], v[2])    
}

TrayIcons(traywindow, control)  
{
    Orphans := []
    DetectHiddenWindows, On
    WinGet, pidTaskbar, PID, %traywindow%
    hProc := DllCall("OpenProcess", "Uint", 0x38, "int", 0, "Uint", pidTaskbar)
    pProc := DllCall("VirtualAllocEx", "Uint", hProc, "Uint", 0, "Uint", 32, "Uint", 0x1000, "Uint", 0x4)
    SendMessage, 0x418, 0, 0, %control%, %traywindow%
    Loop, %ErrorLevel%
    {
        SendMessage, 0x417, A_Index - 1, pProc, %control%, %traywindow%
        VarSetCapacity(btn, 32, 0), VarSetCapacity(nfo, 32, 0)
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", pProc, "Uint", &btn, "Uint", 32, "Uint", 0)  
        If !(dwData := NumGet(btn, 12)) 
            dwData := NumGet(btn, 16, "int64")  
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", dwData, "Uint", &nfo, "Uint", 32, "Uint", 0)
        If NumGet(btn,12)
            hWnd := NumGet(nfo, 0), uID := NumGet(nfo, 4)  
        Else 
            hWnd := NumGet(nfo, 0, "int64"), uID := NumGet(nfo, 8)  
        WinGet, pid, PID, ahk_id %hWnd% 
        If pid =
            Orphans[A_Index] := [hWnd, uID]
    }
    DllCall("VirtualFreeEx", "Uint", hProc, "Uint", pProc, "Uint", 0, "Uint", 0x8000)
    DllCall("CloseHandle", "Uint", hProc)
    Return Orphans
}

GetTrayBar()
{
    ControlGet, hParent, hWnd,, TrayNotifyWnd1, ahk_class Shell_TrayWnd
    ControlGet, hChild, hWnd,, ToolbarWindow321, ahk_id %hParent%
    Loop
    {
        ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class Shell_TrayWnd
        If (hWnd == hChild)
            idxTB := A_Index
        If !hWnd || (hWnd == hChild)
            Break
    }
    Return idxTB
} 

RemoveTrayIcon(hWnd, uID, nMsg = 0, hIcon = 0, nRemove = 2)
{
    NumPut(VarSetCapacity(ni,444,0), ni)
    NumPut(hWnd, ni, 4)
    NumPut(uID, ni, 8)
    NumPut(1|2|4, ni, 12)
    NumPut(nMsg, ni, 16)
    NumPut(hIcon, ni, 20)
    Return DllCall("shell32\Shell_NotifyIconA", "Uint", nRemove, "Uint", &ni)
} 

Автор, Я так понял, здесь

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

25

Re: AHK: Очистить трей от иконок закрытых приложений

У меня на обеих версиях так работает:

#NoTrayIcon
DeleteDummyIcons()

DeleteDummyIcons()
{
/*
Недокументированная структура TRAYDATA
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
   PtrSize := A_Is64bitOS ? 8 : 4
   WM_USER := 0x400
   TB_BUTTONCOUNT := WM_USER + 24
   TB_GETBUTTON := WM_USER + 23
   SizeOfTBBUTTON := 8 + PtrSize*3
   SizeOfTRAYDATA := 16 + PtrSize*2
   
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   ControlGet, hTray, hwnd,, ToolbarWindow321, ahk_class Shell_TrayWnd
   ControlGet, hOverflow, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
   WinGet, PID, PID, ahk_id %hTray%

   ; создаём буфер в адресном пространстве проводника для чтения данных
   RemoteBuff := New RemoteBuffer(PID, SizeOfTRAYDATA)
   Dummy := []
   Loop 2
   {
      hwnd := A_Index = 1 ? hTray : hOverflow
      SendMessage, TB_BUTTONCOUNT,,,, ahk_id %hwnd%
      Loop % ErrorLevel
      {
         SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr,, ahk_id %hwnd%
         ; получаем структуру TBBUTTON, в ней по смещению 8 + PtrSize адрес структуры TRAYDATA в адресном пространстве проводника
         pTBBUTTON := RemoteBuff.Read(SizeOfTBBUTTON)
         
         ; получаем структуру TRAYDATA
         pTRAYDATA := RemoteBuff.Read(SizeOfTRAYDATA, NumGet(pTBBUTTON+0, 8 + PtrSize) - RemoteBuff.ptr)
         hWndIcon := NumGet(pTRAYDATA+0), uID := NumGet(pTRAYDATA + PtrSize, "UInt")
         
         ; если окна не существует (процесс не существует) — заносим в массив
         if !WinExist("ahk_id" hWndIcon)
            Dummy.Insert({hWnd: hWndIcon, uID: uID})
      }
   }
   DetectHiddenWindows, %DHW_Prev%
   for k, v in Dummy
      RemoveTrayIcon(v.hWnd, v.uID)
}

RemoveTrayIcon(hWnd, uID)
{
   VarSetCapacity(NOTIFYICONDATA, size := A_PtrSize = 8 ? 848 : A_IsUnicode? 828 : 444, 0)
   NumPut(size, NOTIFYICONDATA, "UInt")
   NumPut(hWnd, NOTIFYICONDATA, A_PtrSize)
   NumPut(uID, NOTIFYICONDATA, 2*A_PtrSize)
   DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_DELETE := 2, Ptr, &NOTIFYICONDATA)
   Return
}

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)
      DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, size, UInt, 0)
      VarSetCapacity(LocalBuff, -1)
      Return &LocalBuff
   }
   
   Write(pLocalBuff, size, offset = 0)
   {
      return DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

26

Re: AHK: Очистить трей от иконок закрытых приложений

Ага, этот работает нормально.

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

27

Re: AHK: Очистить трей от иконок закрытых приложений

А я уж подумал, долго не отвечает, наверно систему к чертям снесло.

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

28

Re: AHK: Очистить трей от иконок закрытых приложений

В этот раз запускал с закрытыми глазами, но с верой в тебя

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

29

Re: AHK: Очистить трей от иконок закрытых приложений

Сократил там нем немного, можно одним массивом Dummy обойтись. Что касается Коллекции, то мне кажется, тут нужно шире посмотреть на этот вопрос, там ведь главная фишка кода в том, что он получает информацию об иконках трея для всех процессов, а использовать эту информацию для удаления пустых иконок — лишь частный случай.

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

30

Re: AHK: Очистить трей от иконок закрытых приложений

Ну хорошо. Например надо вызвать контекстное меню определённой иконки, как это организовать?

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

31

Re: AHK: Очистить трей от иконок закрытых приложений

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

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

32

Re: AHK: Очистить трей от иконок закрытых приложений

А нет, вспомнил, уже писал такое. Нужно считать

IntPtr hwnd;
uint uID;
uint uCallbackMessage;

из TRAYDATA и послать в окно, связанное с иконкой, соответствующее сообщение. Так можно вызвать контекстное меню первой по порядку иконки в трее:

#NoTrayIcon
idx := 1
PostMessage2TrayIcon(idx, "Tray", WM_RBUTTONDOWN := 0x204, WM_RBUTTONUP := 0x205)
Return

PostMessage2TrayIcon(idx, TrayOrOverflow, messages*)
{
   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-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

33

Re: AHK: Очистить трей от иконок закрытых приложений

Так значит лучше клик правой кнопкой... Кстати как получить координаты.
И можно ли получить хэндл меню иконки, чтобы показать его в нужных координатах этим способом.

И теоретический вопрос, в чём всё таки принципиальное отличие твоего метода от этого http://www.autohotkey.com/board/topic/8 … ayorphans/.

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

34

Re: AHK: Очистить трей от иконок закрытых приложений

По координатам попробовал, тогда меню появляется внизу экрана, и тоже не со всеми иконками работает:

idx := 2

#NoTrayIcon
SizeOfRect := 16
WM_USER := 0x400
TB_GETITEMRECT := WM_USER + 29

DetectHiddenWindows, On
ControlGet, hWnd, hwnd,, ToolbarWindow321, ahk_class Shell_TrayWnd
WinExist("ahk_id" hWnd)
WinGet, PID, PID

RemoteBuff := New RemoteBuffer(PID, SizeOfRect)

SendMessage, TB_GETITEMRECT, idx - 1, RemoteBuff.ptr
pRect := RemoteBuff.Read(SizeOfRect)
x := NumGet(pRect + 0, "UInt"), y := NumGet(pRect + 4, "UInt")   ; координаты относительно окна ToolbarWindow321

ControlFocus
ControlClick, % "x" x + 5 " y" y + 5,,, R,, Pos D
Sleep, 100
ControlClick, % "x" x + 5 " y" y + 5,,, R,, Pos U
Return

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

Как получить хэндл, не знаю.
Мой способ отличается универсальностью, там только под 32 бита.

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

35

Re: AHK: Очистить трей от иконок закрытых приложений

позапускать скрипт на 64-битном интерпретаторе

Так иконка не исчезает сразу. Но если после перезапустить этот скрипт (про иконку которого разговор) то она становится опять же прозрачна.

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

36

Re: AHK: Очистить трей от иконок закрытых приложений

А это только одного скрипта касается, или любого AHK-скрипта?

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

37

Re: AHK: Очистить трей от иконок закрытых приложений

Видимо одного.

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

38

Re: AHK: Очистить трей от иконок закрытых приложений

Поймал этот эффект, сейчас подумаю.

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

39

Re: AHK: Очистить трей от иконок закрытых приложений

У меня без глюков на обоих интерпретаторах работает в таком виде:

#NoTrayIcon
DeleteDummyIcons()

DeleteDummyIcons()
{
/*
Недокументированная структура TRAYDATA
typedef TRAYDATA
{
IntPtr hwnd;
uint uID;
uint uCallbackMessage;
uint Reserved;
uint Reserved2;
IntPtr hIcon;
}
*/
   PtrSize := A_Is64bitOS ? 8 : 4
   WM_USER := 0x400
   TB_BUTTONCOUNT := WM_USER + 24
   TB_GETBUTTON := WM_USER + 23
   TB_DELETEBUTTON := WM_USER + 22
   WM_SETTINGCHANGE := 0x1A
   SizeOfTBBUTTON := 8 + PtrSize*3
   SizeOfTRAYDATA := 16 + PtrSize*2
   
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   ControlGet, hTray, hwnd,, ToolbarWindow321, ahk_class Shell_TrayWnd
   ControlGet, hOverflow, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
   WinGet, PID, PID, ahk_id %hTray%

   ; создаём буфер в адресном пространстве проводника для чтения данных
   RemoteBuff := New RemoteBuffer(PID, SizeOfTRAYDATA)
   Loop 2
   {
      hwnd := A_Index = 1 ? hTray : hOverflow
      SendMessage, TB_BUTTONCOUNT,,,, ahk_id %hwnd%
      i := -1
      Loop % ErrorLevel
      {
         SendMessage, TB_GETBUTTON, ++i, RemoteBuff.ptr,, ahk_id %hwnd%
         ; получаем структуру TBBUTTON, в ней по смещению 8 + PtrSize адрес структуры TRAYDATA в адресном пространстве проводника
         pTBBUTTON := RemoteBuff.Read(SizeOfTBBUTTON)
         
         ; получаем структуру TRAYDATA, первый член её — связанное с иконкой окно
         pTRAYDATA := RemoteBuff.Read(SizeOfTRAYDATA, NumGet(pTBBUTTON+0, 8 + PtrSize) - RemoteBuff.ptr)
         
         ; если окна не существует (процесс не существует) — удаляем иконку
         if !WinExist("ahk_id" NumGet(pTRAYDATA+0))
         {
            SendMessage, TB_DELETEBUTTON, i--,,, ahk_id %hwnd%
            SendMessage, WM_SETTINGCHANGE,,,, ahk_class Shell_TrayWnd
         }
      }
   }
   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 ""
      
      this.size := size
   }
   
   __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)
      DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, size, UInt, 0)
      VarSetCapacity(LocalBuff, -1)
      Return &LocalBuff
   }
   
   Write(pLocalBuff, size, offset = 0)
   {
      return DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
   }
}

То-есть, скрипт путается из-за собственной появляющейся иконки.

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

40

Re: AHK: Очистить трей от иконок закрытых приложений

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

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

41

Re: AHK: Очистить трей от иконок закрытых приложений

А опять же, если перезагрузиться и попробовать сначала на x64?

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

42

Re: AHK: Очистить трей от иконок закрытых приложений

Что то Я уже очкую. Сейчас перезагрузился, а очень нужная мне иконка совсем пропала, хэлп.

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

43

Re: AHK: Очистить трей от иконок закрытых приложений

А в NotifyIconOverflowWindow смотрел?

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

44

Re: AHK: Очистить трей от иконок закрытых приложений

Очень интересно, если удалить строку с прежней иконкой в этом скрипте, или прописать другую то всё равно пусто. Если же оставить параметр пустым:

Menu, Tray, Icon 

хоть стандартную видно, немного отлегло, но хочется вернуть.

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

45 (изменено: serzh82saratov, 2014-04-24 00:39:34)

Re: AHK: Очистить трей от иконок закрытых приложений

 
А в NotifyIconOverflowWindow смотрел?

Ну конечно. Нет даже пустого места.

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

46

Re: AHK: Очистить трей от иконок закрытых приложений

Удалось выйти из положения так:

 
Menu, Tray, Icon
Menu, Tray, Icon, keys.ico

Почему-то...

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

47

Re: AHK: Очистить трей от иконок закрытых приложений

Если какие-то проблемы с иконками остались, глянь сюда и сюда.

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

48

Re: AHK: Очистить трей от иконок закрытых приложений

Спасибо за линки. Теперь уже как наберусь храбрости...

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

49

Re: AHK: Очистить трей от иконок закрытых приложений

teadrinker
Это вроде хорошо чистит:


#SingleInstance Force
#NoTrayIcon
#NoEnv
ListLines Off
SetBatchLines -1

ComObjError(false)
DetectHiddenWindows, On

For i, class in ["Shell_TrayWnd", "NotifyIconOverflowWindow"]
{
    ControlGet, wnd, Hwnd, , ToolbarWindow321, ahk_class %class% ahk_exe explorer.exe
    Acc := AccGet("4", wnd)
    Loop % Max := Acc.accChildCount
        SendMessage, 0x200, 0, % AccLocation(wnd, Acc, Max - A_Index + 1), , ahk_id %wnd%
}
ExitApp



AccLocation(id, Acc, Child=0) {
    WinGetPos, cX, cY, , , ahk_id %id%
    Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), Child)
    y := NumGet(y,0,"int") - cY + (NumGet(h,0,"int") // 2), x := NumGet(x,0,"int") - cX + (NumGet(w,0,"int") // 2)
    Return ((y<<16)^x)
}

AccGet(ChildPath, id) {
    AccObj := AccObjectFromWindow(id, 0)
    if ComObjType(AccObj, "Name") != "IAccessible"
        ErrorLevel := "Could not access an IAccessible Object"
    else
    {
        Loop Parse, ChildPath, .
        {
            Children := Acc_Children(AccObj), m2:=A_LoopField
            if Not Children.HasKey(A_LoopField)
                    throw
                AccObj := Children[m2]
        }
        Return AccObj
    }
}


AccObjectFromWindow(hWnd, idObject = -4) {
    AccInit()
    If    DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
    Return    ComObjEnwrap(9,pacc,1)
}

AccChildren(Acc)  {
    if ComObjType(Acc,"Name") != "IAccessible"
        ErrorLevel := "Invalid IAccessible Object"
    else {
        AccInit(), cChildren:=Acc.accChildCount, Children:=[]
        if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
            Loop %cChildren%
                i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):
            Return Children.MaxIndex()?Children:
        } else
            ErrorLevel := "AccessibleChildren DllCall Failed"
    }
    if Acc_Error()
        throw Exception(ErrorLevel,-1)
}

AccInit()  {
    Static    h
    If Not    h
        h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}

Смотрел ещё это обсуждение, тут предлагают WM_PAINT, но я не разобрался.

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

50

Re: AHK: Очистить трей от иконок закрытых приложений

Глючно, у меня в результате работы этого кода посреди экрана выскочило трей-меню одной из иконок. Кроме того, это то, что называется "костыль", всё равно, что мышкой по трею поводить.

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

51

Re: AHK: Очистить трей от иконок закрытых приложений

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

Может ещё попробовать сообщение WM_LBUTTONUP 0x0202 и\или с впарам поигратся, но у меня глюков не было.

В этом скрипте интересный метод удаления иконки, правда я не разобрался до конца.

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

52

Re: AHK: Очистить трей от иконок закрытых приложений

Так у меня и мой способ без проблем работает.

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

53

Re: AHK: Очистить трей от иконок закрытых приложений

Но это у тебя, вот если бы кто то ещё отписался, что у него тоже работает без проблем на х32.

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

54

Re: AHK: Очистить трей от иконок закрытых приложений

serzh82saratov пишет:

В этом скрипте интересный метод удаления иконки, правда я не разобрался до конца.

Если у тебя этот метод работает без глюков, могу свой скрипт под него переделать.

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

55

Re: AHK: Очистить трей от иконок закрытых приложений

Давай.

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

56

Re: AHK: Очистить трей от иконок закрытых приложений

На скорую руку подрихтовал, полёт нормальный.


1:: NoTrayOrphans()

NoTrayOrphans()
{
    TrayInfo := TrayIcons("ahk_class Shell_TrayWnd", "ToolbarWindow32" . GetTrayBar())  
        . TrayIcons("ahk_class NotifyIconOverflowWindow", "ToolbarWindow321")
 
    Loop, Parse, TrayInfo, `n
    {  
        PID := StrX(A_Loopfield, "| PID: ", " |") 
        If !PID
            RemoveTrayIcon(StrX(A_Loopfield, "| hWnd: ", " |"), StrX(A_Loopfield, "| uID: ", " |"))   
    }
}

TrayIcons(traywindow, control)  
{
    DetectHiddenWindows, On
    WinGet, pidTaskbar, PID, %traywindow%
    hProc := DllCall("OpenProcess", "Uint", 0x38, "int", 0, "Uint", pidTaskbar)
    pProc := DllCall("VirtualAllocEx", "Uint", hProc, "Uint", 0, "Uint", 32, "Uint", 0x1000, "Uint", 0x4)
    SendMessage, 0x418, 0, 0, %control%, %traywindow%
    Loop, %ErrorLevel%
    {
        SendMessage, 0x417, A_Index - 1, pProc, %control%, %traywindow%
        VarSetCapacity(btn, 32, 0), VarSetCapacity(nfo, 32, 0)
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", pProc, "Uint", &btn, "Uint", 32, "Uint", 0)
        iBitmap := NumGet(btn, 0)
        idn := NumGet(btn, 4)
        Statyle := NumGet(btn, 8)
        If dwData := NumGet(btn, 12)
            iString := NumGet(btn, 16)
        Else
        {
            dwData := NumGet(btn, 16, "int64")
            iString := NumGet(btn, 24, "int64")
        }
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", dwData, "Uint", &nfo, "Uint", 32, "Uint", 0)
        If NumGet(btn,12)
        {
            hWnd := NumGet(nfo, 0)
            uID := NumGet(nfo, 4)
            nMsg := NumGet(nfo, 8)
            hIcon := NumGet(nfo, 20)
        }
        Else
        {
            hWnd := NumGet(nfo, 0, "int64")
            uID := NumGet(nfo, 8)
            nMsg := NumGet(nfo, 12)
            hIcon := NumGet(nfo, 24)
        }
        WinGet, pid, PID, ahk_id %hWnd%
        WinGet, sProcess, ProcessName, ahk_id %hWnd%
        WinGetClass, sClass, ahk_id %hWnd% 
        VarSetCapacity(sTooltip, 128)
        VarSetCapacity(wTooltip, 128*2)
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", iString, "Uint", &wTooltip, "Uint", 128*2, "Uint", 0)
        DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", wTooltip, "int", -1, "str", sTooltip, "int", 128, "Uint", 0, "Uint", 0)
        sTrayIcons .= "| Pid: " pid " | uID: " uID " | hWnd: " hWnd " |`n" 
    }
    DllCall("VirtualFreeEx", "Uint", hProc, "Uint", pProc, "Uint", 0, "Uint", 0x8000)
    DllCall("CloseHandle", "Uint", hProc)
    Return sTrayIcons
}

GetTrayBar()
{
    ControlGet, hParent, hWnd,, TrayNotifyWnd1, ahk_class Shell_TrayWnd
    ControlGet, hChild, hWnd,, ToolbarWindow321, ahk_id %hParent%
    Loop
    {
        ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class Shell_TrayWnd
        If (hWnd == hChild)
            idxTB := A_Index
        If !hWnd || (hWnd == hChild)
            Break
    }
    Return idxTB
}

StrX(H, BS = "", ES = "", Tr = 1, ByRef OS = 1)
{
    Return (SP := InStr(H, BS, 0, OS)) && (L := InStr(H, ES, 0, SP + StrLen(BS))) && (OS := L + StrLen(ES)) ? SubStr(H, SP := Tr ? SP + StrLen(BS) : SP, (Tr ? L : L + StrLen(ES)) -SP) : ""
}

RemoveTrayIcon(hWnd, uID, nMsg = 0, hIcon = 0, nRemove = 2)
{
    NumPut(VarSetCapacity(ni,444,0), ni)
    NumPut(hWnd, ni, 4)
    NumPut(uID, ni, 8)
    NumPut(1|2|4, ni, 12)
    NumPut(nMsg, ni, 16)
    NumPut(hIcon, ni, 20)
    Return DllCall("shell32\Shell_NotifyIconA", "Uint", nRemove, "Uint", &ni)
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

57

Re: AHK: Очистить трей от иконок закрытых приложений

Вынес в отдельную тему.

58 (изменено: Drugoy, 2016-09-12 23:40:09)

Re: AHK: Очистить трей от иконок закрытых приложений

+ открыть спойлер

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

РЕЗЮМЕ ПОСТА
Задача: очистить трей (системный лоток, system tray) от иконок закрытых приложений (осиротевшие иконки, tray orphans).

У задачи есть несколько решений и они базируются на разных подходах.

Подход 1 - базируется на том, что осиротевшие иконки вычищаются из трэя сами (системой), если навести на них курсором. Но водить курсором (MouseMove) не обязательно: достаточно просто отправлять трею соответствующие сообщения.

WM_MOUSEMOVE := 0x200	; Сообщение для отправки.
coords := (y << 16) + x		; 'x' и 'y' координаты преобразовываются в единое число.
PostMessage, WM_MOUSEMOVE, 0, coords, controlNN, wintitle

Тут сразу стоит отметить, что controlNN похоже зависит от версии ОС: на Windows10, судя по чужим сообщениям,  оно принимает значение "ToolbarWindow322", в то время как на других версиях -  "ToolbarWindow321".
wintitle же тоже может принимать 2 значения: "ahk_class Shell_TrayWnd" и "ahk_class NotifyIconOverflowWindow": первое - это обычная область трея, а второе - область куда ОСью по-умолчанию автоматически скрываются неиспользуемые иконки из трея (это поведение отключаемо).

Подход 2 - базируется на цепочке из 3 действий:
1. сначала собирается информация о каждой иконке в трее;
2. затем циклически для каждой иконки выполняется проверка "а жив ли процесс, связанный с hwnd этой иконки?";
3. если на шаге 2 ответ негативный, то иконка убирается одним из двух способов:
А. Надёжный, полагающийся на hWnd и uID иконки (первый из них практически гарантирует уникальность):

NIM_DELETE := 0x2	; выбираем сообщение, означающее удаление иконки.
; NID - структура, которая формируется несколькими NumPut'ами и содержит hWnd и uID иконки. Более подробно здесь: https://msdn.microsoft.com/en-us/library/windows/desktop/bb773352
DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_DELETE, "Ptr", &NID)

Б. Менее надёжный, просто по индексу иконки (соответственно, следует учитывать сдвиг после каждой исчезнувшей иконки):

; idx - индекс иконки в трее.
WM_SETTINGCHANGE := 0x1A, TB_DELETEBUTTON := 0x416
SendMessage, TB_DELETEBUTTON, idx, 0, controlNN, wintitle		; TB_DELETEBUTTON - https://msdn.microsoft.com/en-us/library/windows/desktop/bb787309(v=vs.85).aspx
SendMessage, WM_SETTINGCHANGE, 0, 0,, wintitle

Хороший пример реализации подхода №2-А, основывающийся на использовании 3-ёх функций из библиотеки TrayIcon Library от FanaticGuru (которая в свою очередь основывается на трудах других людей).

Вот и всё, что есть, а остальное - либо повторения, либо вариации реализации вышеописанных методов, например:
- представленный в этой теме скрипт DeleteDummyIcons() от teadrinker'а - является ещё одной реализацией подхода №2-А, но отличается (от реализации упомянутой выше) иной организацией кода по сбору информации обо всех иконках в трее.

p.s.: шаг 3 из подхода 2-А - позволяет удалять любые иконки в трее, не обязательно tray orphans.

59

Re: AHK: Очистить трей от иконок закрытых приложений

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

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

60

Re: AHK: Очистить трей от иконок закрытых приложений

+ открыть спойлер

teadrinker, спасибо, что поправили, я думал, что это ошибка, просто не критическая (типа использования неверного типа данных, что тоже не всегда приводит к проблемам), а сейчас покопался в документации - и оказалось, что там это отмечено.
Правда, следует помнить, что:
- все типы со звёздочкой - в кавычки брать надо (звёздочку можно заменить на "P" и тогда кавычки не обязательны.
- 'ptr' можно обозвать и переменную, что способно запутать как пишущего, так и читающего код.
- следует помнить, что вне DllCall (например, в NumPut) - кавычки уже обязательны, что способно запутать пишущего код.
Так что проще не экономить на кавычках (вы же не экономите, скажем, на пробелах после запятых-разделителей?) и всегда их употреблять, как правило хорошего тона.

Возник сопутствующий вопрос: получать информацию о каждой иконке и проверять жив ли связанный с ней процесс - это немножко оверкилл для случая, когда заранее известно, какой процесс будет убит так, что от него может остаться иконка (если у процесса была иконка в трее).
Можно ли как-то в этом случае выполнить очистку такой иконки (если она есть) чисто по pid ещё живого процесса (или hwnd его основного окна)?
У меня никак не получилось: подход №1 в этом случае не применим, а в подходе №2 требуется uID.
Вот у всех AutoHotkey скриптов uID у иконок в трее статичный и равен 1028 (AHK_NOTIFYICON), а вот у других иконок uID, получается надо вычитывать из памяти.
Другого способа нет?

61

Re: AHK: Очистить трей от иконок закрытых приложений

Drugoy пишет:

'ptr' можно обозвать и переменную, что способно запутать как пишущего, так и читающего код

В современном AHK нет необходимости так делать. Это использовалось раньше при переходе с AHK-basic на L, т. к. в первой версии нет типа ptr.

Drugoy пишет:

Так что проще не экономить на кавычках (вы же не экономите, скажем, на пробелах после запятых-разделителей?)

Дело вкуса, отсутствие пробелов после запятой вредит читабельностьи, чего неё скажешь об отсутствии кавычкек в типе. Достаточно запомнить, что в NumPut/Get они нужны, а в DllCall не обязательны.

Другого способа нет?

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

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