SunAndSuch wrote:I can find out the number of the column, but I need the text of its header.
Are you able to determine which column was clicked?SunAndSuch wrote:Anyway, is there some other way of finding out which column number the mouse has clicked?
You have to allocate a RECT in the remote process (OpenProcess, VirtualAllocEx, WriteProcessMemory, ReadProcessMemory).SunAndSuch wrote:Then I check the coordinates and they are all zero.
Thank you, problem solved . But I still don't understand why it is not needed in WinSpy.teadrinker wrote:Here is the wrong size, cbHDITEM is needed.
Code: Select all
; Returns an object containing the text and width of each item of a remote SysHeader32 control
GetHeaderInfo(hHeader) {
Static MAX_TEXT_LENGTH := 260
, MAX_TEXT_SIZE := MAX_TEXT_LENGTH * (A_IsUnicode ? 2 : 1)
WinGet PID, PID, ahk_id %hHeader%
; Open the process for read/write and query info.
; PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION
If !(hProc := DllCall("OpenProcess", "UInt", 0x438, "Int", False, "UInt", PID, "Ptr")) {
Return
}
; Should we use the 32-bit struct or the 64-bit struct?
If (A_Is64bitOS) {
Try DllCall("IsWow64Process", "Ptr", hProc, "int*", Is32bit := true)
} Else {
Is32bit := True
}
RPtrSize := Is32bit ? 4 : 8
cbHDITEM := (4 * 6) + (RPtrSize * 6)
; Allocate a buffer in the (presumably) remote process.
remote_item := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0
, "uPtr", cbHDITEM + MAX_TEXT_SIZE
, "UInt", 0x1000, "UInt", 4, "Ptr") ; MEM_COMMIT, PAGE_READWRITE
remote_text := remote_item + cbHDITEM
; Prepare the HDITEM structure locally.
VarSetCapacity(HDITEM, cbHDITEM, 0)
NumPut(0x3, HDITEM, 0, "UInt") ; mask (HDI_WIDTH | HDI_TEXT)
NumPut(remote_text, HDITEM, 8, "Ptr") ; pszText
NumPut(MAX_TEXT_LENGTH, HDITEM, 8 + RPtrSize * 2, "Int") ; cchTextMax
; Write the local structure into the remote buffer.
DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", remote_item, "Ptr", &HDITEM, "uPtr", cbHDITEM, "Ptr", 0)
HDInfo := {}
VarSetCapacity(HDText, MAX_TEXT_SIZE)
SendMessage 0x1200, 0, 0,, ahk_id %hHeader% ; HDM_GETITEMCOUNT
Loop % (ErrorLevel != "FAIL") ? ErrorLevel : 0 {
; Retrieve the item text.
SendMessage, % (A_IsUnicode) ? 0x120B : 0x1203, A_Index - 1, remote_item,, ahk_id %hHeader% ; HDM_GETITEMW
If (ErrorLevel == 1) { ; Success
DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", remote_item, "Ptr", &HDITEM, "uPtr", cbHDITEM + MAX_TEXT_SIZE, "Ptr", 0)
DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", remote_text, "Ptr", &HDText, "uPtr", MAX_TEXT_SIZE, "Ptr", 0)
} Else {
HDText := ""
}
HDInfo.Push({"Width": NumGet(HDITEM, 4, "UInt"), "Text": HDText})
}
; Release the remote memory and handle.
DllCall("VirtualFreeEx", "Ptr", hProc, "Ptr", remote_item, "UPtr", 0, "UInt", 0x8000) ; MEM_RELEASE
DllCall("CloseHandle", "Ptr", hProc)
Return HDInfo
}
Try this:SunAndSuch wrote:And unsurprisingly, the PtInRect also returns 0.
Code: Select all
#SingleInstance Force
#NoEnv
Global hHeader
; Let's pretend this is a ListView from a remote process.
Gui Add, ListView, hWndhLV x0 y0 w410 h252, Column 1|Column 2
SendMessage 0x101F, 0, 0,, ahk_id %hLV% ; LVM_GETHEADER
hHeader := ErrorLevel
Gui Show, w620 h420, Window
; In your script you'll need to use a hotkey, not WM_LBUTTONDOWN.
OnMessage(0x201, "OnWM_LBUTTONDOWN")
Return
GuiEscape:
GuiClose:
ExitApp
OnWM_LBUTTONDOWN(wParam, lParam, msg, hWnd) {
If (hWnd == hHeader) {
;VarSetCapacity(PT, 8, 0)
;DllCall("GetCursorPos", "Ptr", &PT)
CoordMode Mouse, Client
MouseGetPos PX, PY
Loop 2 { ; Column count
VarSetCapacity(RECT, 16, 0)
SendMessage 0x1207, A_Index - 1, &RECT,, ahk_id %hHeader% ; HDM_GETITEMRECT
If (ErrorLevel && ErrorLevel != "FAIL") {
/*
; Not working
If (DllCall("PtInRect", "Ptr", &RECT, "Ptr", &PT)) {
MsgBox % A_Index
Break
}
*/
If (PtInRect(NumGet(RECT, 0, "Int")
, NumGet(RECT, 4, "Int")
, NumGet(RECT, 8, "Int")
, NumGet(RECT, 12, "Int")
, PX, PY)) {
MsgBox Column %A_Index%
Break
}
}
}
}
Return 1
}
PtInRect(RLeft, RTop, RRight, RBottom, PX, PY) {
Return (((PX >= RLeft) && (PX <= RRight)) && ((PY >= RTop) && (PY <= RBottom)))
}