How can I get the text of the column header of a SysListView32? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

How can I get the text of the column header of a SysListView32?

29 Jul 2018, 16:26

Hi!
I have an external program, containing a "SysListView321" with a "SysHeader321" on top of it and I'd like to extract the text from the header. Specifically I am interested in the text of the column I click. I can find out the number of the column, but I need the text of its header. I've searched quite a bit, but didn't find any solution. Any help would be appreciated.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How can I get the text of the column header of a SysListView32?

29 Jul 2018, 16:48

This library has JEE_LVHGetText and JEE_AccCtlGetText. Cheers.
GUIs via DllCall: get/set internal/external control text - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=40514
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
Alguimist
Posts: 428
Joined: 05 Oct 2015, 16:41
Contact:

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 05:56

This is the function I use in WinSpy:

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, "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
}
Last edited by Alguimist on 05 Aug 2018, 16:53, edited 2 times in total.
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 06:37

Thanks for the quick answers!
jeeswg, I downloaded your code (and the Acc library), but stumbled on the call to some nonexistent functions SendMessage(0xE, 0, 0,, "ahk_id " hCtl), JEE_DCOpenProcess(0x438, 0, vPID). Where can I get those?
Alguimist, I have run your function, but it returns all texts empty and all widths 0 (which is not correct).
Windows 10, Ahk v1 x64-bit.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 07:31

- The additional functions are in the second codebox on the thread linked earlier.
- I'll add a comment on the thread.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 08:54

Arrrghhh... I am just blind :crazy:, of course they are there. Thanks a lot jeeswg, it works great now!
Windows 10, Ahk v1 x64-bit.
User avatar
Alguimist
Posts: 428
Joined: 05 Oct 2015, 16:41
Contact:

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 09:02

For some reason the isolated function is not working with AHK 64-bit, but if you check the "Extra" tab of WinSpy, the information is displayed, no matter if executed with AHK 32 or 64-bit.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 13:09

Alguimist wrote:For some reason the isolated function is not working with AHK 64-bit

Code: Select all

DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", remote_item, "Ptr", &HDITEM, "uPtr", MAX_TEXT_SIZE, "Ptr", 0)
Here is the wrong size, cbHDITEM is needed.
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 16:29

Yeah, it works when called from "WinSpy.ahk".
However, now I have a different problem. I thought I could determine which column I clicked the mouse (comparing the mouse X coordinate with the X of the ListView + column widths starting at the column zero until I got sum widths > mouse X), but since the columns can be reordered, I need to know their order. I've tried to use just me's LV_EX_GetColumnOrder() here, but the SendMessage, 0x103B inside the function returns false, and thus the function does too. Anyway, is there some other way of finding out which column number the mouse has clicked?
By the way, WinSpy is an awesome tool, I think I'll be trying some alchemy with it :-).
Windows 10, Ahk v1 x64-bit.
User avatar
Alguimist
Posts: 428
Joined: 05 Oct 2015, 16:41
Contact:

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 18:37

SunAndSuch wrote:Anyway, is there some other way of finding out which column number the mouse has clicked?
Maybe something like HDM_GETITEMRECT (0x1207) and PtInRect.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How can I get the text of the column header of a SysListView32?

30 Jul 2018, 20:39

- Did you pass it the hWnd of the listview (not the header)?
- Actually, that function appears to be written for internal listviews only.
- Try JEE_LVGetColOrder, designed for internal and external listviews.

Code: Select all

;warning: such functions can potentially crash programs, save any work before testing

;[need functions from here:]
;GUIs via DllCall: get/set internal/external control text - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=40514

;==================================================

;pass listview hWnd (not listview header hWnd)
;for local controls only
JEE_LVGetColOrderLocal(hCtl, vSep:="")
{
	hLVH := SendMessage(0x101F,,,, "ahk_id " hCtl) ;LVM_GETHEADER := 0x101F
	vCountCol := SendMessage(0x1200,,,, "ahk_id " hLVH) ;HDM_GETITEMCOUNT := 0x1200
	vData := ""
	VarSetCapacity(vData, vCountCol*4, 0)
	SendMessage(0x103B, vCountCol, &vData,, "ahk_id " hCtl) ;LVM_GETCOLUMNORDERARRAY := 0x103B
	if (vSep = "")
	{
		oOutput := []
		Loop, % vCountCol
			oOutput.Push(NumGet(&vData, A_Index*4-4, "Int")+1)
		return oOutput
	}
	else
	{
		vOutput := ""
		Loop, % vCountCol
			vOutput .= NumGet(&vData, A_Index*4-4, "Int")+1 vSep
		return SubStr(vOutput, 1, -StrLen(vSep))
	}
}

;==================================================

;pass listview hWnd (not listview header hWnd)
JEE_LVGetColOrder(hCtl, vSep:="")
{
	vErr := A_PtrSize=8 && JEE_WinIs64Bit(hCtl) ? -1 : 0xFFFFFFFF
	vScriptPID := DllCall("kernel32\GetCurrentProcessId", UInt)
	vPID := WinGetPID("ahk_id " hCtl)
	if (vPID = vScriptPID)
		vIsLocal := 1, vPIs64 := (A_PtrSize=8)

	if !hLVH := SendMessage(0x101F,,,, "ahk_id " hCtl) ;LVM_GETHEADER := 0x101F
		return
	if !vCountCol := SendMessage(0x1200,,,, "ahk_id " hLVH) ;HDM_GETITEMCOUNT := 0x1200
		return
	if (vCountCol = vErr) ;-1
		return

	if !vIsLocal
	{
		if !hProc := JEE_DCOpenProcess(0x438, 0, vPID)
			return
		if A_Is64bitOS && !DllCall("kernel32\IsWow64Process", Ptr,hProc, PtrP,vIsWow64Process)
			return
		vPIs64 := !vIsWow64Process
	}

	vPtrType := vPIs64?"Int64":"Int"
	vSize := vCountCol*4
	VarSetCapacity(vData, vSize, 0)

	if !vIsLocal
	{
		if !pBuf := JEE_DCVirtualAllocEx(hProc, 0, vSize, 0x3000, 0x4)
			return
	}
	else
		pBuf := &vData

	SendMessage(0x103B, vCountCol, pBuf,, "ahk_id " hCtl) ;LVM_GETCOLUMNORDERARRAY := 0x103B
	if !vIsLocal
	{
		JEE_DCReadProcessMemory(hProc, pBuf, &vData, vSize, 0)
		JEE_DCVirtualFreeEx(hProc, pBuf, 0, 0x8000)
		JEE_DCCloseHandle(hProc)
	}
	if (vSep = "")
	{
		oOutput := []
		Loop, % vCountCol
			oOutput.Push(NumGet(&vData, A_Index*4-4, "Int")+1)
		return oOutput
	}
	else
	{
		vOutput := ""
		Loop, % vCountCol
			vOutput .= NumGet(&vData, A_Index*4-4, "Int")+1 vSep
		return SubStr(vOutput, 1, -StrLen(vSep))
	}
}

;==================================================

;pass listview hWnd (not listview header hWnd)
;for local controls only
JEE_LVSetColOrderLocal(hCtl, oList, vSep:="")
{
	if !IsObject(oList)
		oList := StrSplit(oList, vSep)
	if !(vCountCol := oList.Length())
		return
	VarSetCapacity(vData, vCountCol*4)
	for _, vValue in oList
		NumPut(vValue-1, &vData, A_Index*4-4, "Int")
	SendMessage(0x103A, vCountCol, &vArray,, "ahk_id " hCtl) ;LVM_SETCOLUMNORDERARRAY := 0x103A
}

;==================================================

;pass listview hWnd (not listview header hWnd)
JEE_LVSetColOrder(hCtl, oList, vSep:="")
{
	if !IsObject(oList)
		oList := StrSplit(oList, vSep)
	if !(vCountCol := oList.Length())
		return

	vErr := A_PtrSize=8 && JEE_WinIs64Bit(hCtl) ? -1 : 0xFFFFFFFF
	vScriptPID := DllCall("kernel32\GetCurrentProcessId", UInt)
	vPID := WinGetPID("ahk_id " hCtl)
	if (vPID = vScriptPID)
		vIsLocal := 1, vPIs64 := (A_PtrSize=8)

	if !hLVH := SendMessage(0x101F,,,, "ahk_id " hCtl) ;LVM_GETHEADER := 0x101F
		return
	if !vCountCol := SendMessage(0x1200,,,, "ahk_id " hLVH) ;HDM_GETITEMCOUNT := 0x1200
		return
	if (vCountCol = vErr) ;-1
		return

	if !vIsLocal
	{
		if !hProc := JEE_DCOpenProcess(0x438, 0, vPID)
			return
		if A_Is64bitOS && !DllCall("kernel32\IsWow64Process", Ptr,hProc, IntP,vIsWow64Process)
			return
		vPIs64 := !vIsWow64Process
	}

	vPtrType := vPIs64?"Int64":"Int"
	vSize := vCountCol*4
	VarSetCapacity(vData, vCountCol*4)
	for _, vValue in oList
		NumPut(vValue-1, &vData, A_Index*4-4, "Int")

	if !vIsLocal
	{
		if !pBuf := JEE_DCVirtualAllocEx(hProc, 0, vSize, 0x3000, 0x4)
			return
		JEE_DCWriteProcessMemory(hProc, pBuf, &vData, vSize, 0)
	}
	else
		pBuf := &vData

	SendMessage(0x103A, vCountCol, pBuf,, "ahk_id " hCtl) ;LVM_SETCOLUMNORDERARRAY := 0x103A

	if !vIsLocal
	{
		JEE_DCVirtualFreeEx(hProc, pBuf, 0, 0x8000)
		JEE_DCCloseHandle(hProc)
	}
}

;==================================================
Last edited by jeeswg on 17 Feb 2019, 17:52, edited 2 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

Re: How can I get the text of the column header of a SysListView32?

31 Jul 2018, 01:33

jeeswg wrote:- Did you pass it the hWnd of the listview (not the header)?
Yes, I passed the hWnd of the listview.
Now there are again two functions I can not find: JEE_WinIs64Bit and WinGetPID. I assume the latter one should look something like:

Code: Select all

WinGetPID(hCtl) {
	WinGet,cPid,PID,%hCtl%
	return cPid
}
?
Windows 10, Ahk v1 x64-bit.
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

Re: How can I get the text of the column header of a SysListView32?

31 Jul 2018, 09:07

Alguimist wrote:Maybe something like HDM_GETITEMRECT (0x1207) and PtInRect.
Thanks for the suggestion. I am just learning DllCall, so I have tried:

Code: Select all

ControlGet,hCtl,hwnd,,SysListView321,%winTit%
VarSetCapacity(pt,8,0)
DllCall("GetCursorPos","Ptr",&pt)
SendMessage,0x1207,1,&rect,,ahk_id %hCtl% ;HDM_GETITEMRECT=0x1207
DllCall("PtInRect","Ptr",&rect,"Ptr",&pt)
, but with no success. The "PtInRect" function always returns 0.
By the way, when I do:

Code: Select all

ptX:=NumGet(&pt,0,"UInt")
ptY:=NumGet(&pt,1,"UInt")
, the ptX gets reasonable coordinates, while and ptY gets a 9-digit integer.
Windows 10, Ahk v1 x64-bit.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How can I get the text of the column header of a SysListView32?

31 Jul 2018, 09:18

- I've done an overhaul of both codeboxes here. They now match my latest versions.
GUIs via DllCall: get/set internal/external control text - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=40514
- Everything should be there now.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

Re: How can I get the text of the column header of a SysListView32?

01 Aug 2018, 14:25

jeeswg wrote:- I've done an overhaul of both codeboxes here. They now match my latest versions.
GUIs via DllCall: get/set internal/external control text - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=40514
- Everything should be there now.
Ok... so I would need many functions from AHK v2 to run your code, right (I am currently in AHK v1)?

To the other part. I am wondering what I am doing wrong here:

Code: Select all

ControlGet,hCtl,hwnd,,SysListView321,%winTit%
VarSetCapacity(pt,8)
GetCursorPos:=DllCall("GetCursorPos","Ptr",&pt)
;When I check the cursor coordinates, they look reasonable:
ptX:=NumGet(pt,0,"UInt") ; = integer within the screen resolution
ptY:=NumGet(pt,4,"UInt") ; = integer within the screen resolution
;Then I try to get the coordinates of the rectangle:
VarSetCapacity(rect,16)
SendMessage,0x1207,2,&rect,,ahk_id %hCtl% ;HDM_GETITEMRECT=0x1207
;Then I check the coordinates and they are all zero:
rectTopX:=NumGet(rect,0,"UInt") ; = 0
rectTopY:=NumGet(rect,4,"UInt") ; = 0
rectBotX:=NumGet(rect,8,"UInt") ; = 0
rectBotY:=NumGet(rect,12,"UInt") ; = 0
;And unsurprisingly, the PtInRect also returns 0:
PtInRect:=DllCall("PtInRect","Ptr",&rect,"Ptr",&pt) ; = 0
;Even if I try NumPut, for example:
NumPut(100,rect,0,"UInt")
NumPut(200,rect,4,"UInt")
NumPut(1400,rect,8,"UInt")
NumPut(1300,rect,12,"UInt")
;and then PtInRect, it still returns 0, even though the mouse is clearly in the specified rectangle.
Windows 10, Ahk v1 x64-bit.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How can I get the text of the column header of a SysListView32?

01 Aug 2018, 14:33

- It needs code from 2 codeboxes and code from 2 libraries, I've updated the description, here:
GUIs via DllCall: get/set internal/external control text - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=40514
- I program using AHK v1 + 'AHK v2 functions for AHK v1'. I would like to program in a completely two-way compatible way, but Loop remains a problem. (I have mentioned this in my Wish List 2.0.)
- If I tried to maintain 2 versions of all of my functions, I would have time for nothing else.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

Re: How can I get the text of the column header of a SysListView32?

01 Aug 2018, 14:54

jeeswg wrote:- It needs code from 2 codeboxes and code from 2 libraries, I've updated the description, here:
GUIs via DllCall: get/set internal/external control text - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=40514
- I program using AHK v1 + 'AHK v2 functions for AHK v1'. I would like to program in a completely two-way compatible way, but Loop remains a problem. (I have mentioned this in my Wish List 2.0.)
- If I tried to maintain 2 versions of all of my functions, I would have time for nothing else.
Which two libraries? In your description it says
To run: the code from both codeboxes is needed, and from Acc.ahk.
I can not find functions WinGetClass, WinGetPID, ControlGetText, ControlGetStyle and ControlSend so far.
Windows 10, Ahk v1 x64-bit.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How can I get the text of the column header of a SysListView32?

01 Aug 2018, 15:03

I updated the description, it says:
To run: the code from both codeboxes is needed, and from two libraries: Acc.ahk and 'AHK v2 functions for AHK v1'.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
SunAndSuch
Posts: 46
Joined: 05 Oct 2015, 12:11

Re: How can I get the text of the column header of a SysListView32?

01 Aug 2018, 15:32

Now that makes sense. But

Code: Select all

oColOrd:=JEE_LVGetColOrder(LVhwnd)
Loop,18
	res.=oColOrd[A_Index] ","
gives res = "1,11,3,4,8,5,6,1,1,1,7864321,3145780,3145777,1,7864321,53,3670017,1,"
Windows 10, Ahk v1 x64-bit.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How can I get the text of the column header of a SysListView32?

01 Aug 2018, 15:44

Are you using x32 or x64? Does it work on any other listview controls? Does it have 18 columns?
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: jaka1, marypoppins_1 and 135 guests