<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Серый форум &mdash; AHK: Получение данных об иконке в трее под курсором]]></title>
	<link rel="self" href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=10556&amp;type=atom" />
	<updated>2015-04-05T23:52:33Z</updated>
	<generator>PunBB</generator>
	<id>https://forum.script-coding.com/viewtopic.php?id=10556</id>
		<entry>
			<title type="html"><![CDATA[AHK: Получение данных об иконке в трее под курсором]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=93046#p93046" />
			<content type="html"><![CDATA[<p>Скрипт выводит данные об иконке в трее или в окне <em>NotifyIconOverflowWindow</em> по клику правой кнопкой над ней при удержании Ctrl.<br /></p><div class="codebox"><pre><code>^RButton::   ; Ctrl + RButton
   if !oTrayIconInfo := GetTrayIconInfoFromMousePos()  {
      MsgBox, Не удалось получить информацию!
      Return
   }

   MsgBox, % &quot;PID = &quot;         oTrayIconInfo.PID
         . &quot;`nProcessName = &quot; oTrayIconInfo.ProcessName
         . &quot;`nProcessPath = &quot; oTrayIconInfo.ProcessPath
         . &quot;`nCommandLine = &quot; oTrayIconInfo.CommandLine
         . &quot;`nhWnd = &quot;        oTrayIconInfo.hWnd
         . &quot;`nTooltip = &quot;     oTrayIconInfo.Tooltip
   Return
   
Esc:: ExitApp

GetTrayIconInfoFromMousePos()
{
/*
Недокументированная структура 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, TB_GETITEMRECT := WM_USER + 29
      , PtrSize := A_Is64bitOS ? 8 : 4, SizeOfTBBUTTON := 8 + PtrSize*3, SizeOfTRAYDATA := 16 + PtrSize*2, SizeOfiString := 256
   ; проверяем, находится ли курсор над треем или над окном NotifyIconOverflowWindow   
   if !hToolbar := ControlMousePos(XM, YM)
      Return, 0, DllCall(&quot;MessageBox&quot;, Ptr, 0, Str, &quot;Курсор не над треем&quot;, Str, &quot;&quot;, UInt, 0)
   
   WinExist(&quot;ahk_id&quot; hToolbar)
   WinGet, PID, PID
   ; создаём буфер в адресном пространстве процесса explorer.exe (которому принадлежит и окно трея)
   if !IsObject(RemoteBuff := New RemoteBuffer(PID, SizeOfTBBUTTON))
      Return, 0, DllCall(&quot;MessageBox&quot;, Ptr, 0, Str, &quot;Не удалось создать удалённый буфер`nОшибка &quot; A_LastError, Str, &quot;&quot;, UInt, 0)
   
   WinGetPos, xTB, yTB
   POINT := (XM - xTB) | (YM - yTB) &lt;&lt; 32
   
   SendMessage, TB_BUTTONCOUNT
   Loop % ErrorLevel  {
      ; информация, возвращаемая сообщениями TB_GETITEMRECT и TB_GETBUTTON, находится в адресном пространстве
      ; процесса explorer.exe, поэтому для её чтения пользуемся созданным ранее буфером
      ; TB_GETITEMRECT возвращает в структуре RECT координаты иконки с индексом A_Index - 1 относительно окна трея или окна NotifyIconOverflowWindow
      SendMessage, TB_GETITEMRECT, A_Index - 1, RemoteBuff.ptr
      RemoteBuff.Read(RECT, 16)
      ; сравниваем координаты иконки с координатами мыши
      if !DllCall(&quot;PtInRect&quot;, Ptr, &amp;RECT, Int64, POINT)
         continue
      ; если координаты мыши лежат внутри площади иконки, получаем и возвращаем информацию о ней
      SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr
      RemoteBuff.Read(TBBUTTON, SizeOfTBBUTTON)
      
      DHW_Prev := A_DetectHiddenWindows
      DetectHiddenWindows, On
      ; получаем смещение структуры TRAYDATA относительно нашего буфера
      TraydataOffset := NumGet(&amp;TBBUTTON + 8 + PtrSize) - RemoteBuff.ptr
      ; получаем смещение строки со всплывающей подсказкой иконки относительно нашего буфера
      TooltipOffset := NumGet(&amp;TBBUTTON + 8 + PtrSize*2) - RemoteBuff.ptr
      RemoteBuff.Read(TRAYDATA, SizeOfTRAYDATA, TraydataOffset), WinExist(&quot;ahk_id&quot; hWnd := NumGet(&amp;TRAYDATA))
      RemoteBuff.Read(String, SizeOfiString, TooltipOffset), Tooltip := StrGet(&amp;String, &quot;UTF-16&quot;)
      WinGet, Name, ProcessName
      WinGet, ProcessPath, ProcessPath
      WinGet, PID, PID
      DetectHiddenWindows, %DHW_Prev%
      
      Return {ProcessName: Name, PID: PID, ProcessPath: ProcessPath, hWnd: Format(&quot;{:#x}&quot;, hWnd)
            , CommandLine: ComObjGet(&quot;winmgmts:&quot;).Get(&quot;Win32_Process.Handle=&quot; . PID).CommandLine, Tooltip: Tooltip}
   }
}

ControlMousePos(ByRef X, ByRef Y)
{
   CoordMode, Mouse
   MouseGetPos, X, Y, hWnd, hControl, 2
   WinGetClass, Class, ahk_id %hWnd%
   
   if Class not in NotifyIconOverflowWindow,Shell_TrayWnd
      Return
   
   if (Class = &quot;NotifyIconOverflowWindow&quot;)
      ControlGet, hToolbar, hwnd,, ToolbarWindow321, ahk_id %hWnd%
   else  {
      for k, v in [&quot;TrayNotifyWnd&quot;, &quot;SysPager&quot;, &quot;ToolbarWindow32&quot;]
         hToolbar := DllCall(&quot;FindWindowEx&quot;, Ptr, k = 1 ? hWnd : hToolbar, Ptr, 0, Str, v, UInt, 0, Ptr)
      if (hToolbar != hControl)
         Return
   }
   Return hToolbar
}

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(&quot;OpenProcess&quot;, UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))
         Return
      
      if !(this.ptr := DllCall(&quot;VirtualAllocEx&quot;, Ptr, this.hProc, UInt, 0, Ptr, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
         Return, &quot;&quot;, DllCall(&quot;CloseHandle&quot;, Ptr, this.hProc)
   }
   
   __Delete()
   {
      DllCall(&quot;VirtualFreeEx&quot;, Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
      DllCall(&quot;CloseHandle&quot;, Ptr, this.hProc)
   }
   
   Read(ByRef LocalBuff, size, offset = 0)
   {
      VarSetCapacity(LocalBuff, size, 0)
      if !DllCall(&quot;ReadProcessMemory&quot;, Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &amp;LocalBuff, Ptr, size, Ptr, 0)
         Return, 0, DllCall(&quot;MessageBox&quot;, Ptr, 0, Str, &quot;Не удалось прочитать данные`nОшибка &quot; A_LastError, Str, &quot;&quot;, UInt, 0)
      Return 1
   }
}</code></pre></div><p>Вопросы можно задать в <a href="http://forum.script-coding.com/viewtopic.php?id=10480">этой теме</a>.</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2015-04-05T23:52:33Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=93046#p93046</id>
		</entry>
</feed>
