#NoEnv
RemoveTip() ; удаление дефолтной подсказки при наведении на иконку скрипта
OnMessage(0x404, Func("AHK_NOTIFYICON").Bind("Заголовок", "Мой текст", 1))
Return
RemoveTip() {
static uID := 0x404, NIF_TIP := 4, NIM_MODIFY := 1
VarSetCapacity(NOTIFYICONDATA, size := A_PtrSize = 8 ? 848 : A_IsUnicode? 828 : 444, 0)
NumPut(size, NOTIFYICONDATA, "UInt")
NumPut(A_ScriptHwnd, NOTIFYICONDATA, A_PtrSize)
NumPut(uID, NOTIFYICONDATA, 2*A_PtrSize, "UInt")
NumPut(NIF_TIP, NOTIFYICONDATA, 2*A_PtrSize + 4, "UInt")
NumPut(0, NOTIFYICONDATA, 4*A_PtrSize + 8)
DllCall("shell32\Shell_NotifyIcon", "UInt", NIM_MODIFY, Ptr, &NOTIFYICONDATA)
}
AHK_NOTIFYICON(title, text, options, wp, lp) {
static WM_MOUSEMOVE := 0x200, showtip := []
if (lp = WM_MOUSEMOVE && !showtip[1]) {
showtip[1] := true
MouseGetPos,,,, hToolbar, 2
TrayTip, % title, % text, 30, % options
timer := Func("TraytipDel").Bind(showtip, hToolbar)
SetTimer, % timer, 100
}
}
TraytipDel(info, hToolbar) {
Loop 1 {
if oPos := GetMousePosOnToolbar() {
VarSetCapacity(RECT, 16, 0)
GetScriptIconPos(hToolbar, RECT)
WinGetPos, xTB, yTB,,, ahk_id %hToolbar%
POINT := (oPos.x - xTB) | (oPos.y - yTB) << 32
if DllCall("PtInRect", Ptr, &RECT, Int64, POINT)
break
}
try SetTimer,, Delete
info[1] := false
TrayTip
}
}
GetMousePosOnToolbar() {
CoordMode, Mouse
MouseGetPos, X, Y, hwnd
WinGetClass, winClass, ahk_id %hwnd%
if winClass not in Shell_TrayWnd,NotifyIconOverflowWindow,tooltips_class32
Return
Return {x: X, y: Y}
}
GetScriptIconPos(hToolbar, ByRef RECT) {
static WM_USER := 0x400, TB_BUTTONCOUNT := WM_USER + 24, TB_GETBUTTON := WM_USER + 23, TB_GETITEMRECT := WM_USER + 29
, PtrSize := A_Is64bitOS ? 8 : 4, szTBBUTTON := 8 + PtrSize*3, szTRAYDATA := 16 + PtrSize*2
WinExist("ahk_id" hToolbar)
WinGet, PID, PID
RemoteBuff := New RemoteBuffer(PID, szTBBUTTON)
SendMessage, TB_BUTTONCOUNT
Loop % ErrorLevel {
SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr
pTBBUTTON := RemoteBuff.Read(szTBBUTTON)
TraydataOffset := NumGet(pTBBUTTON + 8 + PtrSize) - RemoteBuff.ptr
pTRAYDATA := RemoteBuff.Read(szTRAYDATA, TraydataOffset)
hWnd := NumGet(pTRAYDATA + 0, PtrSize = 4 ? "UInt" : "UInt64")
if (hWnd != A_ScriptHwnd)
continue
SendMessage, TB_GETITEMRECT, A_Index - 1, RemoteBuff.ptr
pRECT := RemoteBuff.Read(16)
DllCall("RtlMoveMemory", Ptr, &RECT, Ptr, pRECT, Ptr, 16)
break
}
}
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", Ptr, this.hProc, Ptr, 0, Ptr, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
Return, "", DllCall("CloseHandle", Ptr, this.hProc)
this.hHeap := DllCall("GetProcessHeap", Ptr)
}
__Delete() {
DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
DllCall("CloseHandle", Ptr, this.hProc)
DllCall("HeapFree", Ptr, this.hHeap, UInt, 0, Ptr, this.pHeap)
}
Read(size, offset = 0) {
(this.pHeap && DllCall("HeapFree", Ptr, this.hHeap, UInt, 0, Ptr, this.pHeap))
this.pHeap := DllCall("HeapAlloc", Ptr, this.hHeap, UInt, HEAP_ZERO_MEMORY := 0x8, Ptr, size, Ptr)
if !DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, this.pHeap, Ptr, size, Int, 0)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось прочитать данные`nОшибка " A_LastError, Str, "", UInt, 0)
Return this.pHeap
}
Write(pLocalBuff, size, offset = 0) {
if !res := DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, Ptr, size, PtrP, writtenBytes)
DllCall("MessageBox", Ptr, 0, Str, "Не удалось записать данные`nОшибка " A_LastError, Str, "", UInt, 0)
Return writtenBytes
}
}