-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy pathEnumToolbarButtons.ahk
134 lines (123 loc) · 4.42 KB
/
EnumToolbarButtons.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
EnumToolbarButtons(ctrlhwnd, is_apply_scale:=false) {
; Thanks to LabelControl code from
; https://www.donationcoder.com/Software/Skrommel/
;
; ctrlhwnd is the toolbar hwnd.
; Return an array of objects, with element:
; * .x .y .w .h (button position relative to the toolbar)
; * .cmd (command id of the button)
; * .text (text displayed on the button)
;
; is_apply_scale should keep false; true is only for testing purpose
arbtn := []
ControlGetPos, ctrlx, ctrly, ctrlw, ctrlh, , ahk_id %ctrlhwnd%
WinGet, pid_target, PID, ahk_id %ctrlhwnd%
hpRemote := DllCall( "OpenProcess"
, "uint", 0x18 ; PROCESS_VM_OPERATION|PROCESS_VM_READ
, "int", false
, "uint", pid_target )
; hpRemote: Remote process handle
if(!hpRemote) {
tooltip, % "Autohotkey: Cannot OpenProcess(pid=" . pid_target . ")"
return
}
remote_buffer := DllCall( "VirtualAllocEx"
, "uint", hpRemote
, "Ptr", 0 ; LPVOID lpAddress ("uint" tolerable)
, "uint", 0x1000 ; size to allocate, 4KB
, "uint", 0x1000 ; MEM_COMMIT
, "uint", 0x4 ) ; PAGE_READWRITE
x1=
x2=
y1=
WM_USER:=0x400
TB_GETSTATE:=WM_USER+18
TB_GETBITMAP := (WM_USER + 44) ; only for test
TB_GETBUTTONSIZE := (WM_USER + 58) ; only for test
TB_GETBUTTON:=WM_USER+23
TB_GETBUTTONTEXTW := WM_USER+75 ; I always get UTF-16 string from the toolbar // ANSI: WM_USER+45
TB_GETITEMRECT:=WM_USER+29
TB_BUTTONCOUNT:=WM_USER+24
SendMessage, %TB_BUTTONCOUNT%,0,0, , ahk_id %ctrlhwnd%
buttons := ErrorLevel
;tooltip, buttons=%buttons% ; OK
VarSetCapacity( rect, 16, 0 )
VarSetCapacity( BtnStruct, 32, 0 ) ; Winapi TBBUTTON struct(32 bytes on x64, 20 bytes on x86)
/*
typedef struct _TBBUTTON {
int iBitmap;
int idCommand;
BYTE fsState;
BYTE fsStyle;
#ifdef _WIN64
BYTE bReserved[6] // padding for alignment
#elif defined(_WIN32)
BYTE bReserved[2] // padding for alignment
#endif
DWORD_PTR dwData;
INT_PTR iString;
} TBBUTTON, NEAR* PTBBUTTON, FAR* LPTBBUTTON;
*/
Loop,%buttons%
{
; Try to get button text. Two steps:
; 1. get command-id from button-index,
; 2. get button text from comand-id
SendMessage, %TB_GETBUTTON%, % A_Index-1, remote_buffer, , ahk_id %ctrlhwnd%
ReadRemoteBuffer(hpRemote, remote_buffer, BtnStruct, 32)
idButton := NumGet(BtnStruct, 4, "int")
;
; SendMessage, %TB_GETSTATE%, %idButton%, 0, , ahk_id %ctrlhwnd% ; hope that 4KB is enough ; just a test
SendMessage, %TB_GETBUTTONTEXTW%, %idButton%, remote_buffer, , ahk_id %ctrlhwnd% ; hope that 4KB is enough
btntextchars := ErrorLevel
if(btntextchars>0){
btntextbytes := A_IsUnicode ? btntextchars*2 : btntextchars
VarSetCapacity(BtnTextBuf, btntextbytes+2, 0) ; +2 is for trailing-NUL
ReadRemoteBuffer(hpRemote, remote_buffer, BtnTextBuf, btntextbytes)
BtnText := StrGet(&BtnTextBuf, "UTF-16")
} else {
BtnText := ""
}
;FileAppend, % A_Index . ":" . idButton . "(" . btntextchars . ")" . BtnText . "`n", _emeditor_toolbar_buttons.txt ; debug
SendMessage,%TB_GETITEMRECT%,% A_Index-1, remote_buffer, , ahk_id %ctrlhwnd%
ReadRemoteBuffer(hpRemote, remote_buffer, rect, 16)
oldx1:=x1
oldx2:=x2
oldy1:=y1
x1 := NumGet(rect, 0, "int")
x2 := NumGet(rect, 8, "int")
y1 := NumGet(rect, 4, "int")
y2 := NumGet(rect, 12, "int")
if(is_apply_scale) {
scale := Get_DPIScale()
x1 /= scale
y1 /= scale
x2 /= scale
y2 /= scale
}
If (x1=oldx1 And y1=oldy1 And x2=oldx2)
Continue
If (x2-x1<10)
Continue
If (x1>ctrlw Or y1>ctrlh)
Continue
arbtn.Insert( {"x":x1, "y":y1, "w":x2-x1, "h":y2-y1, "cmd":idButton, "text":BtnText} )
;line:=100000000+Floor((ctrly+y1)/same)*10000+(ctrlx+x1)
;lines=%lines%%line%%A_Tab%%ctrlid%%A_Tab%%class%`n
}
result := DllCall( "VirtualFreeEx"
, "uint", hpRemote
, "uint", remote_buffer
, "uint", 0
, "uint", 0x8000 ) ; MEM_RELEASE
result := DllCall( "CloseHandle", "uint", hpRemote )
return arbtn
}
ReadRemoteBuffer(hpRemote, RemoteBuffer, ByRef LocalVar, bytes) {
result := DllCall( "ReadProcessMemory"
, "Ptr", hpRemote
, "Ptr", RemoteBuffer
, "Ptr", &LocalVar
, "uint", bytes
, "uint", 0 )
}