1

Тема: AHK: Выбор пункта из меню в трее

Вопрос, каким кодом можно открыть меню в трее этого приложения и выбрать пункт под стрелочкой?
https://pp.userapi.com/c840620/v840620673/4c537/U_6RWHpwwdU.jpg

Скрипт должен отключать мой Мегафон можем и включать через меню мегафон модема в трее

Покумекаем о делах наших скорбных.

2

Re: AHK: Выбор пункта из меню в трее

Зачем открывать? Через сообщения можно выбрать пункт меню.

3

Re: AHK: Выбор пункта из меню в трее

Интересует данный вопрос, тока не конкретно в этой программе в теме, а вообще. Как активировать контекстное меню программы в трее и выбрать нужный пункт?

4

Re: AHK: Выбор пункта из меню в трее

Присоединяюсь к svoboden.

5 (изменено: svoboden, 2018-03-22 23:34:22)

Re: AHK: Выбор пункта из меню в трее

Vicoriyan пишет:

Как активировать контекстное меню программы в трее и выбрать нужный пункт?

Зачем активировать? В большинстве случаев работает так:

DetectHiddenWindows, on
PostMessage, 0x111, 1005,,, Заголовок программы ; вместо 1005 отловить нужно сообщение.

p.s. Заголовок программы нужно подобрать самому, т.е. оставить одно-два слова.
p.p.s. Проверено на опыте.

6

Re: AHK: Выбор пункта из меню в трее

А как мне узнать, какое мне число нужно за месть 1005? Пробовал определить с помощью Winspector, ничего не вышло.

7

Re: AHK: Выбор пункта из меню в трее

Spy++.

8 (изменено: Vicoriyan, 2018-03-23 13:20:34)

Re: AHK: Выбор пункта из меню в трее

Разобрался как найти это число. Спасибо.

9

Re: AHK: Выбор пункта из меню в трее

Не могу понять в чем дело. PostMessage работает после, как вручную воспользуешься один раз этим меню, но когда запускаю приложение и не воспользовавшись меню, PostMessage не работает. Пробовал идентифицировать и прописывать ID, PID окна и прогресса, но результата не дало.

10

Re: AHK: Выбор пункта из меню в трее

Для меню в трее много библиотек написано, вот вариант, кажется от teadrinker (пример для uTorrent, оба хоткея делают одно и тоже):

#SingleInstance Force
#NoEnv
DetectHiddenWindows On

Title := "ahk_exe uTorrent.exe"
1::
	Path := ["Download Limit", ["Неограниченно", "150 kB/s"]]
	MenuSelect(Path, Title)
	Return
2::
	Path := ["6&", ["1&", "4&"]]
	MenuSelect(Path, Title)
	Return

Esc::ExitApp

MenuSelect(Path, Title) {
	WinGet, PID, PID, % "ahk_id" hWnd := WinExist(Title)
	PostMessage2TrayIconProcID(PID, WM_RBUTTONDOWN := 0x204, WM_RBUTTONUP := 0x205)
	WinWait, % "ahk_class #32768 ahk_pid" PID, , 0.5
	If ErrorLevel
		Return
	SendMessage, 0x1E1    ;  MN_GETHMENU
	If !(hMenu := ErrorLevel)
		Return
	DllCall("GetCursorPos", "int64P", pt)
	X := pt << 32 >> 32
	Y := pt >> 32
	MenuSelectPath(hMenu, hWnd, Path)
	DllCall("SetCursorPos", "Uint", X, "Uint", Y)
}

MenuSelectPath(hMenu, hWnd, Path, Key = 1) {
	Static MF_BYPOSITION := 0x400, MF_CHECKED := 0x00000008, MF_DISABLED := 0x00000002, MF_GRAYED := 0x00000001
		, MF_MENUBARBREAK := 0x00000020, MF_MENUBREAK := 0x00000040, MF_SEPARATOR := 0x00000800
	Item := Path[Key]
	If IsObject(Item)
		Item := Path[Key][1]
	If (Item ~= "^\d+&$")
		ItemNum := SubStr(Item, 1, -1) - 1
	Loop, % DllCall("GetMenuItemCount", "Ptr", hMenu)
	{
		idx := A_Index - 1
		If (Item ~= "^\d+&$")
		{
			If (ItemNum != idx)
				Continue
			If (Key < Path.MaxIndex())
			{
				MenuSetCursor(hMenu, hWnd, idx)
				Return MenuSelectPath(DllCall("GetSubMenu", "Ptr", hMenu, "Uint", idx), hWnd, Path, Key + 1)
			}
			Find := 1
			Break
		}
		Else
		{
			idn := DllCall("GetMenuItemID", "Ptr", hMenu, "int", idx)
			nSize++ := DllCall("GetMenuString", "Ptr", hMenu, "Uint", idx, "Uint", 0, "Uint", 0, "Uint", MF_BYPOSITION)
			nSize := (nSize * (A_IsUnicode ? 2 : 1))
			VarSetCapacity(sString, nSize)
			DllCall("GetMenuString", "Ptr", hMenu, "Uint", idx, "Str", sString, "Uint", nSize, "Uint", MF_BYPOSITION)   ; MF_BYPOSITION
			StringReplace, String, sString, &, , 1
			If (Item != String)
				Continue
			If (Key < Path.MaxIndex())
			{
				MenuSetCursor(hMenu, hWnd, idx)
				Return MenuSelectPath(DllCall("GetSubMenu", "Ptr", hMenu, "Uint", idx), hWnd, Path, Key + 1)
			}
			Find := 1
			Break
		}
	}
	If !Find
		Return 0
	If IsObject(Path[Key])
	{
		State := DllCall("GetMenuState", "Ptr", hMenu, "UInt", idx, "UInt", MF_BYPOSITION)
		If (State & MF_CHECKED || State & MF_DISABLED || State & MF_GRAYED || State & MF_MENUBARBREAK || State & MF_MENUBREAK || State & MF_SEPARATOR)
			Return MenuSelectPath(hMenu, hWnd, [Path[Key][2]], 1)
	}
	MenuSetCursor(hMenu, hWnd, idx)
	Return 1
}

MenuSetCursor(hMenu, hWnd, idx) {
	VarSetCapacity(pt, 16, 0)
	DllCall("GetMenuItemRect"
			 , "Ptr", hWnd
			 , "Ptr", hMenu
			 , "UInt", idx
			 , "UInt", &pt)
	x := NumGet(pt, 0), y := NumGet(pt, 4)
	w := NumGet(pt, 8) - x, h := NumGet(pt, 12) - y
	DllCall("SetCursorPos", "Uint", x + w // 2, "Uint", y + h // 2)
	Click
	Sleep 100
}
Return



PostMessage2TrayIconProcID(ProcessPID, 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

	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)
			if (PID = ProcessPID)
			{
				uID := NumGet(pTRAYDATA + PtrSize, "UInt")
				uCallbackMessage := NumGet(pTRAYDATA + PtrSize + 4, "UInt")
				; FocusTrayIcon(hWnd, uID)
				for i, message in messages
					PostMessage, uCallbackMessage, uID, message,, % "ahk_id" hWnd
				DetectHiddenWindows, %DHW_Prev%
				Return
			}
		}
	}
	DetectHiddenWindows, %DHW_Prev%
	MsgBox, % "Иконка процесса " . ProcessPID . " не найдена"
}

FocusTrayIcon(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_SETFOCUS := 0x00000003, 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)
		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)
	}
}