Help with focus\select specific line from SysListView321

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Help with focus\select specific line from SysListView321

Post by Tomer » 23 May 2022, 02:23

Hello,

I managed to get all the lines from a window listview by this script line:

Code: Select all

ControlGet, Output, List, , SysListView321, ahk_class MMCMainFrame
MsgBox % Output
I need help with focus\select a specific line in the listview window (by specific name)

Thanks in advance!

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Help with focus\select specific line from SysListView321

Post by mikeyww » 23 May 2022, 03:52

This may lead in the right direction: viewtopic.php?f=76&t=84027viewtopic.php?t=3513

Function .....: ExtListView_ToggleSelection
Description ..: Select/deselect items in the target ListView.

User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 23 May 2022, 04:19

Hey @mikeyww

Thanks for your reply

Can you please post a smaple script that select\focus line from SysListView321 list by a name "c:\" ?

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Help with focus\select specific line from SysListView321

Post by mikeyww » 23 May 2022, 04:24

I did not try the library & other scripts, but it looks like they might fit your needs perfectly. You could test them, right? If a question arises, the authors of those scripts might also be able to provide assistance or helpful guidance. A way to get their attention is to tag them in a post, or to post a reply in those threads.

User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 24 May 2022, 03:51

i managed to select only the first item of the listview by Pressing F1 key,

how can i select a item by his NAME instead ?

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------
; Name .........: ExtListView library
; Description ..: Collection of functions dealing with the ListViews of external processes.
; AHK Version ..: AHK_L 1.1.13.01 x32/64 ANSI/Unicode
; Author .......: Cyruz - http://ciroprincipe.info
; License ......: WTFPL - http://www.wtfpl.net/txt/copying/
; Changelog ....: May  18, 2013 - v0.1 - First revision.
; ..............: Jun. 28, 2013 - v0.2 - Added resizable buffer option.
; ..............: Feb. 04, 2014 - v0.3 - Unicode and x64 compatibility.
; ..............: Apr. 10, 2014 - v1.0 - Code refactoring. Added encoding option and simple error management.
; ..............: May  04, 2014 - v1.1 - Detached the handles and memory allocation code.
; ..............: May  05, 2014 - v1.2 - Created ExtListView_GetAllItems and ExtListView_ToggleSelection functions.
; ..............: May  06, 2014 - v2.0 - Complete rewrite of the library. Code more modular and updateable. Separated 
; ..............:                        code for De/Initialization, GetNextItem and GetItemText.
; ..............: Jul  24, 2017 - v2.1 - Fixed LVITEM size issue.
; ----------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetSingleItem
; Description ..: Get the first item with the desired state.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; ..............: nCol   - Column of the desired item (0-based index).
; Info .........: For more info on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Single item as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetSingleItem(ByRef objLV, sState, nCol) {
    Try {
        
        If ( (nRow  := ExtListView_GetNextItem(objLV, -1, sState)) != 0xFFFFFFFF )
            sItem := ExtListView_GetItemText(objLV, nRow, nCol)
        
    } Catch e
      Throw e
      
    Return (sItem) ? sItem : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetAllItems
; Description ..: Get all items that share the same status on the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: For more infor on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Multidimensional array containing ListView's items. Eg: array[row][column] := "SomeString".
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetAllItems(ByRef objLV, sState:=0x0000) {
    Try {
        
        nRow := -1, objList := []
        Loop
        {
            If ( (nRow := ExtListView_GetNextItem(objLV, nRow, sState)) == 0xFFFFFFFF )
                Break
            x := A_Index, objList[x] := []
            Loop % objLV.cols
                objList[x][A_Index] := ExtListView_GetItemText(objLV, nRow, A_Index-1)
        }
        
    } Catch e
      Throw e
      
    Return ( objList.MaxIndex() ) ? objList : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_ToggleSelection
; Description ..: Select/deselect items in the target ListView.
; Parameters ...: objLV   - External ListView initialized object.
; ..............: bSelect - 1 for selection, 0 for deselection.
; ..............: nItem   - -1 for all items or "n" (0-based) for a specific ListView item.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_ToggleSelection(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0002 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED = 0x0002 or 0x0000 (reset mask).
    NumPut( 0x0002,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetNextItem
; Description ..: Get the next item in the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: nRow   - Row where to start the search for the next item (0-based index).
; ..............: lParam - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: LVM_GETNEXTITEM - http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetNextItem(ByRef objLV, nRow, lParam:=0x0000) {
    ; LVM_GETNEXTITEM = LVM_FIRST (0x1000) + 12 = 0x100C.
    SendMessage, 0x100C, %nRow%, %lParam%,, % "ahk_id " objLV.hlv
    Return ErrorLevel
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetItemText
; Description ..: Get the text of the desired item.
; Parameters ...: objLV - External ListView initialized object.
; ..............: nRow  - Row of the desired item (0-based index).
; ..............: nCol  - Column of the desired item (0-based index).
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetItemText(ByRef objLV, nRow, nCol) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0001,          LVITEM, 0                          ) ; mask = LVIF_TEXT = 0x0001.
    NumPut( nRow,            LVITEM, 4                          ) ; iItem = Row to retrieve (0 = 1st row).
    NumPut( nCol,            LVITEM, 8                          ) ; iSubItem = The column index of the item to retrieve.
    NumPut( objLV.preadbuf,  LVITEM, 20 + (A_PtrSize - 4)       ) ; pszText = Pointer to item text string.
    NumPut( objLV.szreadbuf, LVITEM, 20 + ((A_PtrSize * 2) - 4) ) ; cchTextMax = Number of TCHARs in the buffer.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,objLV.szwritebuf
                                       , UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    
    ; LVM_GETITEMTEXTA = LVM_FIRST (0x1000) + 45  = 0x102D.
    ; LVM_GETITEMTEXTW = LVM_FIRST (0x1000) + 115 = 0x1073.
    LVM_GETITEMTEXT := (objLV.senc == "UTF-8" || objLV.senc == "UTF-16") ? 0x1073 : 0x102D
    SendMessage, %LVM_GETITEMTEXT%, %nRow%, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
    
    VarSetCapacity(cRecvBuf, objLV.szreadbuf, 1)
    If ( !DllCall( "ReadProcessMemory", Ptr,objLV.hproc, Ptr,objLV.preadbuf, Ptr,&cRecvBuf, UInt,objLV.szreadbuf
                                      , Ptr,0 ) )
        Throw Exception("objLV.preadbuf: error reading memory", "ReadProcessMemory", "LastError: " A_LastError)
    
    Return StrGet(&cRecvBuf, objLV.szreadbuf, objLV.senc)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_Initialize
; Description ..: Initialize the object containing ListView's related data.
; Parameters ...: sWnd      - Title of the window containing the ListView.
; ..............: szReadBuf - Size of the buffer used for reading the target process memory. It must be capable enough
; ..............:             to hold the longest cell in the ListView.
; ..............: sEnc      - Target ListView's encoding. "CP0" for ANSI, "UTF-8" or "UTF-16" for Unicode.
; Return .......: objLV            - External ListView initialized object with the following keys:
; ..............: objLV.swnd       - Title of the window owning the ListView.
; ..............: objLV.hwnd       - Handle to the window owning the ListView.
; ..............: objLV.hproc      - Handle to the process owning the ListView.
; ..............: objLV.hlv        - Handle to the ListView.
; ..............: objLV.hhdr       - Handle to the header of the ListView.
; ..............: objLV.rows       - Number of rows in the ListView.
; ..............: objLV.cols       - Number of columns in the ListView.
; ..............: objLV.senc       - Encoding used by the process owning the ListView.
; ..............: objLV.pwritebuf  - Address to the buffer used to write the LVITEM message to the target ListView.
; ..............: objLV.szwritebuf - Size of the write buffer.
; ..............: objLV.preadbuf   - Address to the buffer used to read the answer to the message sent.
; ..............: objLV.szreadbuf  - Size of the read buffer.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_Initialize(sWnd, szReadBuf:=1024, sEnc:="CP0") {
    objLV            := Object()
    objLV.swnd       := sWnd
    objLV.hwnd       := WinExist(sWnd)
    objLV.szwritebuf := (A_OSVersion == "WIN_XP") ? 52 + (A_PtrSize-4)*5 : 60 + (A_PtrSize-4)*7 ; Size of LVITEM
    objLV.szreadbuf  := szReadBuf
    objLV.senc       := sEnc
    
    ControlGet, hLv, Hwnd,, SysListView321, % "ahk_id " objLV.hwnd
    objLV.hlv := hLv
    
    DllCall( "GetWindowThreadProcessId", Ptr,hLv, PtrP,dwProcessId )
    ; PROCESS_VM_OPERATION = 0x0008, PROCESS_VM_READ = 0x0010, PROCESS_VM_WRITE = 0x0020.
    If ( !(objLV.hproc := DllCall( "OpenProcess", UInt,0x0008|0x0010|0x0020, Int,0, UInt,dwProcessId )) )
        Throw Exception("objLV.hproc: error opening process", "OpenProcess", "LastError: " A_LastError)
    
    ; LVM_GETITEMCOUNT = LVM_FIRST (0x1000) + 4 = 0x1004.
    SendMessage, 0x1004, 0, 0,, % "ahk_id " objLV.hlv
    objLV.rows := ErrorLevel
    
    ; LVM_GETHEADER = LVM_FIRST (0x1000) + 31 = 0x101F.
    SendMessage, 0x101F, 0, 0,, % "ahk_id " objLV.hlv
    objLV.hhdr := ErrorLevel
    
    ; HDM_GETITEMCOUNT = HDM_FIRST (0x1200) + 0 = 0x1200.
    SendMessage, 0x1200, 0, 0,, % "ahk_id " objLV.hhdr
    objLV.cols := ErrorLevel
    
    ; Allocate memory on the target process before returning the object.
    If ( !__ExtListView_AllocateMemory(objLV) )
        Throw Exception("Error allocating memory", "__ExtListView_Initialize", "LastError: " A_LastError)
    
    Return objLV
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_DeInitialize
; Description ..: DeInitialize the object.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_DeInitialize(ByRef objLV) {
    ; Free the previously allocated memory on the target process.
    If ( !__ExtListView_DeAllocateMemory(objLV) )
        Throw Exception("Error deallocating memory", "__ExtListView_DeInitialize", "LastError: " A_LastError)
    DllCall( "CloseHandle", Ptr,objLV.hproc )
    objLV := ""
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_CheckInitObject
; Description ..: Check if the object is still referring to a valid ListView.
; Parameters ...: objLV - External ListView initialized object.
; Return .......: 0 if false, handle of the window containing the ListView if true.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_CheckInitObject(ByRef objLV) {
    Return WinExist("ahk_id " objLV.hwnd)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_AllocateMemory
; Description ..: Allocates memory into the target process.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_AllocateMemory(ByRef objLV) {
    ; MEM_COMMIT = 0x1000, PAGE_READWRITE = 0x4.
    If ( !(objLV.pwritebuf := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szwritebuf, UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    If ( !(objLV.preadbuf  := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szreadbuf,  UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    Return 1
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_DeAllocateMemory
; Description ..: Frees previously allocated memory.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_DeAllocateMemory(ByRef objLV) {
    ; MEM_RELEASE = 0x8000.
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("pwritebuf")
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.preadbuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("preadbuf")
    Return 1
}

;~ /* EXAMPLE CODE:

OnExit, QUIT
WINTITLE = Active Directory Users and Computers ahk_class MMCMainFrame
objLV := ExtListView_Initialize(WINTITLE)
HotKey, IfWinActive, %WINTITLE%
HotKey, F1, TOGGLESEL
Return

TOGGLESEL:
( ExtListView_CheckInitObject(objLV) ) ? objLV := ExtListView_Initialize(WINTITLE)
ExtListView_ToggleSelection(objLV, 1, 0)
Return

QUIT:
ExtListView_DeInitialize(objLV)
ExitApp

;~ */


User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Help with focus\select specific line from SysListView321

Post by mikeyww » 24 May 2022, 05:01

I did not try it, but if you can toggle only by number, you can get the list of strings, find your string, and then you know what number it is.

User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 24 May 2022, 05:03

how i get the string ?

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Help with focus\select specific line from SysListView321

Post by mikeyww » 24 May 2022, 05:05

It looks like you would need to try ExtListView_GetAllItems, ExtListView_GetNextItem, or ExtListView_GetItemText. Those functions' parameters are explained in the script.

Code: Select all

LVwindowTitle := "Test" ; Adjust as needed

#Include D:\utils\listviewLibrary.ahk
Gui, Font, s10
Gui, Add, ListView, r10, A|B
LV_Add("", "abc"  , "def")
LV_Add("", "ghi"  , "jkl")
LV_Add("", "ghiff", "jklff")
LV_ModifyCol(1, 50), LV_ModifyCol(2, 50)
Gui, Show,, %LVwindowTitle%

LV            := ExtListView_Initialize(LVwindowTitle)
findText      := "ghi"
row           := row(LV, findText)
MsgBox, 64, Text, Text: %findText%`n`nRow: %row%
findText      := "jklff"
row           := row(LV, findText, 2)
MsgBox, 64, Text, Text: %findText%`n`nRow: %row%
findText      := "bbbbbbbbbbbbbb"
row           := row(LV, findText)
MsgBox, 64, Text, Text: %findText%`n`nRow: %row%

select(LV, "xxghi")
select(LV, "jkl", COL := 2)
; select(LV, "hif")

Return

select(LV, str, col := 1) {            ; Select a row in a ListView, by string
 (row := row(LV, str, col)) && ExtListView_ToggleSelection(LV, SELECT := True, row - 1)
}

row(LV, str, col := 1) {               ; Find string in a ListView column
 ; https://www.autohotkey.com/boards/viewtopic.php?t=3513
 ; https://www.autohotkey.com/boards/viewtopic.php?p=463971#p463971
 Loop {
  next :=       ExtListView_GetNextItem(LV, row := A_Index - 1)
  pos  := Instr(ExtListView_GetItemText(LV, row, col - 1), str)
 } Until (next < 1 || pos)
 Return pos ? row + 1 : 0              ; Return the row number found, or zero
}

GuiClose:
GuiEscape:
ExitApp

User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 29 May 2022, 02:27

@mikeyww thank you very much!
the sample you posted helped me a lot!

I have just one issue for now,

i try to select the row name "test42" - its works but I have to scroll down manually to see the selection,
is there any option to focus the item selection so no need to scroll the listview ?

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------
; Name .........: ExtListView library
; Description ..: Collection of functions dealing with the ListViews of external processes.
; AHK Version ..: AHK_L 1.1.13.01 x32/64 ANSI/Unicode
; Author .......: Cyruz - http://ciroprincipe.info
; License ......: WTFPL - http://www.wtfpl.net/txt/copying/
; Changelog ....: May  18, 2013 - v0.1 - First revision.
; ..............: Jun. 28, 2013 - v0.2 - Added resizable buffer option.
; ..............: Feb. 04, 2014 - v0.3 - Unicode and x64 compatibility.
; ..............: Apr. 10, 2014 - v1.0 - Code refactoring. Added encoding option and simple error management.
; ..............: May  04, 2014 - v1.1 - Detached the handles and memory allocation code.
; ..............: May  05, 2014 - v1.2 - Created ExtListView_GetAllItems and ExtListView_ToggleSelection functions.
; ..............: May  06, 2014 - v2.0 - Complete rewrite of the library. Code more modular and updateable. Separated 
; ..............:                        code for De/Initialization, GetNextItem and GetItemText.
; ..............: Jul  24, 2017 - v2.1 - Fixed LVITEM size issue.
; ----------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetSingleItem
; Description ..: Get the first item with the desired state.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; ..............: nCol   - Column of the desired item (0-based index).
; Info .........: For more info on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Single item as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetSingleItem(ByRef objLV, sState, nCol) {
    Try {
        
        If ( (nRow  := ExtListView_GetNextItem(objLV, -1, sState)) != 0xFFFFFFFF )
            sItem := ExtListView_GetItemText(objLV, nRow, nCol)
        
    } Catch e
      Throw e
      
    Return (sItem) ? sItem : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetAllItems
; Description ..: Get all items that share the same status on the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: For more infor on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Multidimensional array containing ListView's items. Eg: array[row][column] := "SomeString".
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetAllItems(ByRef objLV, sState:=0x0000) {
    Try {
        
        nRow := -1, objList := []
        Loop
        {
            If ( (nRow := ExtListView_GetNextItem(objLV, nRow, sState)) == 0xFFFFFFFF )
                Break
            x := A_Index, objList[x] := []
            Loop % objLV.cols
                objList[x][A_Index] := ExtListView_GetItemText(objLV, nRow, A_Index-1)
        }
        
    } Catch e
      Throw e
      
    Return ( objList.MaxIndex() ) ? objList : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_ToggleSelection
; Description ..: Select/deselect items in the target ListView.
; Parameters ...: objLV   - External ListView initialized object.
; ..............: bSelect - 1 for selection, 0 for deselection.
; ..............: nItem   - -1 for all items or "n" (0-based) for a specific ListView item.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_ToggleSelection(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0002 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED = 0x0002 or 0x0000 (reset mask).
    NumPut( 0x0002,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetNextItem
; Description ..: Get the next item in the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: nRow   - Row where to start the search for the next item (0-based index).
; ..............: lParam - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: LVM_GETNEXTITEM - http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetNextItem(ByRef objLV, nRow, lParam:=0x0000) {
    ; LVM_GETNEXTITEM = LVM_FIRST (0x1000) + 12 = 0x100C.
    SendMessage, 0x100C, %nRow%, %lParam%,, % "ahk_id " objLV.hlv
    Return ErrorLevel
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetItemText
; Description ..: Get the text of the desired item.
; Parameters ...: objLV - External ListView initialized object.
; ..............: nRow  - Row of the desired item (0-based index).
; ..............: nCol  - Column of the desired item (0-based index).
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetItemText(ByRef objLV, nRow, nCol) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0001,          LVITEM, 0                          ) ; mask = LVIF_TEXT = 0x0001.
    NumPut( nRow,            LVITEM, 4                          ) ; iItem = Row to retrieve (0 = 1st row).
    NumPut( nCol,            LVITEM, 8                          ) ; iSubItem = The column index of the item to retrieve.
    NumPut( objLV.preadbuf,  LVITEM, 20 + (A_PtrSize - 4)       ) ; pszText = Pointer to item text string.
    NumPut( objLV.szreadbuf, LVITEM, 20 + ((A_PtrSize * 2) - 4) ) ; cchTextMax = Number of TCHARs in the buffer.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,objLV.szwritebuf
                                       , UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    
    ; LVM_GETITEMTEXTA = LVM_FIRST (0x1000) + 45  = 0x102D.
    ; LVM_GETITEMTEXTW = LVM_FIRST (0x1000) + 115 = 0x1073.
    LVM_GETITEMTEXT := (objLV.senc == "UTF-8" || objLV.senc == "UTF-16") ? 0x1073 : 0x102D
    SendMessage, %LVM_GETITEMTEXT%, %nRow%, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
    
    VarSetCapacity(cRecvBuf, objLV.szreadbuf, 1)
    If ( !DllCall( "ReadProcessMemory", Ptr,objLV.hproc, Ptr,objLV.preadbuf, Ptr,&cRecvBuf, UInt,objLV.szreadbuf
                                      , Ptr,0 ) )
        Throw Exception("objLV.preadbuf: error reading memory", "ReadProcessMemory", "LastError: " A_LastError)
    
    Return StrGet(&cRecvBuf, objLV.szreadbuf, objLV.senc)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_Initialize
; Description ..: Initialize the object containing ListView's related data.
; Parameters ...: sWnd      - Title of the window containing the ListView.
; ..............: szReadBuf - Size of the buffer used for reading the target process memory. It must be capable enough
; ..............:             to hold the longest cell in the ListView.
; ..............: sEnc      - Target ListView's encoding. "CP0" for ANSI, "UTF-8" or "UTF-16" for Unicode.
; Return .......: objLV            - External ListView initialized object with the following keys:
; ..............: objLV.swnd       - Title of the window owning the ListView.
; ..............: objLV.hwnd       - Handle to the window owning the ListView.
; ..............: objLV.hproc      - Handle to the process owning the ListView.
; ..............: objLV.hlv        - Handle to the ListView.
; ..............: objLV.hhdr       - Handle to the header of the ListView.
; ..............: objLV.rows       - Number of rows in the ListView.
; ..............: objLV.cols       - Number of columns in the ListView.
; ..............: objLV.senc       - Encoding used by the process owning the ListView.
; ..............: objLV.pwritebuf  - Address to the buffer used to write the LVITEM message to the target ListView.
; ..............: objLV.szwritebuf - Size of the write buffer.
; ..............: objLV.preadbuf   - Address to the buffer used to read the answer to the message sent.
; ..............: objLV.szreadbuf  - Size of the read buffer.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_Initialize(sWnd, szReadBuf:=1024, sEnc:="CP0") {
    objLV            := Object()
    objLV.swnd       := sWnd
    objLV.hwnd       := WinExist(sWnd)
    objLV.szwritebuf := (A_OSVersion == "WIN_XP") ? 52 + (A_PtrSize-4)*5 : 60 + (A_PtrSize-4)*7 ; Size of LVITEM
    objLV.szreadbuf  := szReadBuf
    objLV.senc       := sEnc
    
    ControlGet, hLv, Hwnd,, SysListView321, % "ahk_id " objLV.hwnd
    objLV.hlv := hLv
    
    DllCall( "GetWindowThreadProcessId", Ptr,hLv, PtrP,dwProcessId )
    ; PROCESS_VM_OPERATION = 0x0008, PROCESS_VM_READ = 0x0010, PROCESS_VM_WRITE = 0x0020.
    If ( !(objLV.hproc := DllCall( "OpenProcess", UInt,0x0008|0x0010|0x0020, Int,0, UInt,dwProcessId )) )
        Throw Exception("objLV.hproc: error opening process", "OpenProcess", "LastError: " A_LastError)
    
    ; LVM_GETITEMCOUNT = LVM_FIRST (0x1000) + 4 = 0x1004.
    SendMessage, 0x1004, 0, 0,, % "ahk_id " objLV.hlv
    objLV.rows := ErrorLevel
    
    ; LVM_GETHEADER = LVM_FIRST (0x1000) + 31 = 0x101F.
    SendMessage, 0x101F, 0, 0,, % "ahk_id " objLV.hlv
    objLV.hhdr := ErrorLevel
    
    ; HDM_GETITEMCOUNT = HDM_FIRST (0x1200) + 0 = 0x1200.
    SendMessage, 0x1200, 0, 0,, % "ahk_id " objLV.hhdr
    objLV.cols := ErrorLevel
    
    ; Allocate memory on the target process before returning the object.
    If ( !__ExtListView_AllocateMemory(objLV) )
        Throw Exception("Error allocating memory", "__ExtListView_Initialize", "LastError: " A_LastError)
    
    Return objLV
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_DeInitialize
; Description ..: DeInitialize the object.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_DeInitialize(ByRef objLV) {
    ; Free the previously allocated memory on the target process.
    If ( !__ExtListView_DeAllocateMemory(objLV) )
        Throw Exception("Error deallocating memory", "__ExtListView_DeInitialize", "LastError: " A_LastError)
    DllCall( "CloseHandle", Ptr,objLV.hproc )
    objLV := ""
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_CheckInitObject
; Description ..: Check if the object is still referring to a valid ListView.
; Parameters ...: objLV - External ListView initialized object.
; Return .......: 0 if false, handle of the window containing the ListView if true.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_CheckInitObject(ByRef objLV) {
    Return WinExist("ahk_id " objLV.hwnd)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_AllocateMemory
; Description ..: Allocates memory into the target process.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_AllocateMemory(ByRef objLV) {
    ; MEM_COMMIT = 0x1000, PAGE_READWRITE = 0x4.
    If ( !(objLV.pwritebuf := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szwritebuf, UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    If ( !(objLV.preadbuf  := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szreadbuf,  UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    Return 1
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_DeAllocateMemory
; Description ..: Frees previously allocated memory.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_DeAllocateMemory(ByRef objLV) {
    ; MEM_RELEASE = 0x8000.
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("pwritebuf")
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.preadbuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("preadbuf")
    Return 1
}


LVwindowTitle := "Test" ; Adjust as needed

Gui, Font, s10
Gui, Add, ListView, r10, A|B
LV_Add("", "abc"  , "def")
LV_Add("", "ghi"  , "jkl")
Loop, 50
{
	LV_Add("", "test"A_Index, "mike"A_Index)
}
LV_ModifyCol(1, 50), LV_ModifyCol(2, 50)
Gui, Show,, %LVwindowTitle%


LV            := ExtListView_Initialize(LVwindowTitle)
;~ findText      := "ghi"
;~ row           := row(LV, findText)
;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%
;~ findText      := "jklff"
;~ row           := row(LV, findText, 2)
;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%
;~ findText      := "bbbbbbbbbbbbbb"
;~ row           := row(LV, findText)
;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%

select(LV, "test42")
;~ select(LV, "jkl", COL := 2)
; select(LV, "hif")


MsgBox, "test42" selected - scroll down to see!
Return

select(LV, str, col := 1) {            ; Select a row in a ListView, by string
 (row := row(LV, str, col)) && ExtListView_ToggleSelection(LV, SELECT := True, row - 1)
}

row(LV, str, col := 1) {               ; Find string in a ListView column
 ; https://www.autohotkey.com/boards/viewtopic.php?t=3513
 ; https://www.autohotkey.com/boards/viewtopic.php?p=463971#p463971
 Loop {
  next :=       ExtListView_GetNextItem(LV, row := A_Index - 1)
  pos  := Instr(ExtListView_GetItemText(LV, row, col - 1), str)
 } Until (next < 1 || pos)
 Return pos ? row + 1 : 0              ; Return the row number found, or zero
}

GuiClose:
GuiEscape:
ExitApp

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Help with focus\select specific line from SysListView321

Post by mikeyww » 29 May 2022, 02:44

I do not see an option like that. You could contact the author or reply to the original post with the library.

User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 29 May 2022, 03:16

I managed to solve this with:

Code: Select all

select(LV, "test41")
LV_Modify(LV_GetCount(), "Vis")
But it doesn't work with external listview :(


User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 29 May 2022, 03:55

teadrinker wrote:
29 May 2022, 03:42
LVM_ENSUREVISIBLE
Thanks teadrinker !
can you please share a smaple code how to use this control in ahk ?
i want to select\focus rows in external listview with auto scrolling

User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 29 May 2022, 05:25

mikeyww wrote:
29 May 2022, 02:44
I do not see an option like that. You could contact the author or reply to the original post with the library.
check MrDoge's reply:
viewtopic.php?p=426511#p426511
?

User avatar
boiler
Posts: 16771
Joined: 21 Dec 2014, 02:44

Re: Help with focus\select specific line from SysListView321

Post by boiler » 29 May 2022, 06:21

Did you see the function that was added in the post immediately before yours? It does exactly what you want and what teadrinker suggested.

Code: Select all

ExtListView_EnsureVisible(objLV, Row, fPartialOK:=false)

User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 29 May 2022, 06:58

@boiler Thank you

what im doing worng ?

i want to select\focus the row name "test44" using "ExtListView_EnsureVisible"

Code: Select all

; https://www.autohotkey.com/boards/viewtopic.php?t=3513
; ----------------------------------------------------------------------------------------------------------------------
; Name .........: ExtListView library
; Description ..: Collection of functions dealing with the ListViews of external processes.
; AHK Version ..: AHK_L 1.1.13.01 x32/64 ANSI/Unicode
; Author .......: Cyruz - http://ciroprincipe.info
; License ......: WTFPL - http://www.wtfpl.net/txt/copying/
; Changelog ....: May  18, 2013 - v0.1 - First revision.
; ..............: Jun. 28, 2013 - v0.2 - Added resizable buffer option.
; ..............: Feb. 04, 2014 - v0.3 - Unicode and x64 compatibility.
; ..............: Apr. 10, 2014 - v1.0 - Code refactoring. Added encoding option and simple error management.
; ..............: May  04, 2014 - v1.1 - Detached the handles and memory allocation code.
; ..............: May  05, 2014 - v1.2 - Created ExtListView_GetAllItems and ExtListView_ToggleSelection functions.
; ..............: May  06, 2014 - v2.0 - Complete rewrite of the library. Code more modular and updateable. Separated 
; ..............:                        code for De/Initialization, GetNextItem and GetItemText.
; ..............: Jul  24, 2017 - v2.1 - Fixed LVITEM size issue.
; ----------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetSingleItem
; Description ..: Get the first item with the desired state.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001 ;The item has the focus, so it is surrounded by a standard focus rectangle. Although more than one item may be selected, only one item can have the focus.
; ..............:          LVNI_SELECTED    - 0x0002 ;The item is selected. The appearance of a selected item depends on whether it has the focus and also on the system colors used for selection.
; ..............:          LVNI_CUT         - 0x0004 ;The item is marked for a cut-and-paste operation.
; ..............:          LVNI_DROPHILITED - 0x0008 ;The item is highlighted as a drag-and-drop target.
; ..............: nCol   - Column of the desired item (0-based index).
; Info .........: For more info on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Single item as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetSingleItem(ByRef objLV, sState, nCol) {
    Try {
        
        If ( (nRow  := ExtListView_GetNextItem(objLV, -1, sState)) != -1 )
            sItem := ExtListView_GetItemText(objLV, nRow, nCol)
        
    } Catch e
      Throw e
      
    Return (sItem) ? sItem : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetAllItems
; Description ..: Get all items that share the same status on the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: For more infor on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Multidimensional array containing ListView's items. Eg: array[row][column] := "SomeString".
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetAllItems(ByRef objLV, sState:=0x0000) {
    Try {
        
        nRow := -1, objList := []
        Loop
        {
            If ( (nRow := ExtListView_GetNextItem(objLV, nRow, sState)) == -1 )
                Break
            x := A_Index, objList[x] := []
            Loop % objLV.cols
                objList[x][A_Index] := ExtListView_GetItemText(objLV, nRow, A_Index-1)
        }
        
    } Catch e
      Throw e
      
    Return ( objList.MaxIndex() ) ? objList : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_ToggleSelection
; Description ..: Select/deselect items in the target ListView.
; Parameters ...: objLV   - External ListView initialized object.
; ..............: bSelect - 1 for selection, 0 for deselection.
; ..............: nItem   - -1 for all items or "n" (0-based) for a specific ListView item.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_ToggleSelection(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0002 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED = 0x0002 or 0x0000 (reset mask).
    NumPut( 0x0002,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.
    
    If ( !DllCall( "WriteProcessMemory", "Ptr",objLV.hproc, "Ptr",objLV.pwritebuf, "Ptr",&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv ;LVM_SETITEMSTATE
    ;#####, this works because it's reading from it's OWN MEMORY objLV.pwritebuf
}
ExtListView_ToggleFocusAndSelection(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0003 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED =  0x0002 or 0x0000 (reset mask).
    NumPut( 0x0003,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}
ExtListView_ToggleFocus(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0001 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED =  0x0002 or 0x0000 (reset mask).
    NumPut( 0x0001,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetNextItem
; Description ..: Get the next item in the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: nRow   - Row where to start the search for the next item (0-based index).
; ..............: lParam - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: LVM_GETNEXTITEM - http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetNextItem(ByRef objLV, nRow:=-1, lParam:=0x0000) {
    ; LVM_GETNEXTITEM = LVM_FIRST (0x1000) + 12 = 0x100C.
    SendMessage, 0x100C, %nRow%, %lParam%,, % "ahk_id " objLV.hlv
    Return ErrorLevel << 32 >> 32
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetItemText
; Description ..: Get the text of the desired item.
; Parameters ...: objLV - External ListView initialized object.
; ..............: nRow  - Row of the desired item (0-based index).
; ..............: nCol  - Column of the desired item (0-based index).
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetItemText(ByRef objLV, nRow, nCol) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0001,          LVITEM, 0                          ) ; mask = LVIF_TEXT = 0x0001.
    NumPut( nRow,            LVITEM, 4                          ) ; iItem = Row to retrieve (0 = 1st row).
    NumPut( nCol,            LVITEM, 8                          ) ; iSubItem = The column index of the item to retrieve.
    NumPut( objLV.preadbuf,  LVITEM, 20 + (A_PtrSize - 4)       ) ; pszText = Pointer to item text string.
    NumPut( objLV.szreadbuf, LVITEM, 20 + ((A_PtrSize * 2) - 4) ) ; cchTextMax = Number of TCHARs in the buffer.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,objLV.szwritebuf
                                       , UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    
    ; LVM_GETITEMTEXTA = LVM_FIRST (0x1000) + 45  = 0x102D.
    ; LVM_GETITEMTEXTW = LVM_FIRST (0x1000) + 115 = 0x1073.
    LVM_GETITEMTEXT := (objLV.senc == "UTF-8" || objLV.senc == "UTF-16") ? 0x1073 : 0x102D
    SendMessage, %LVM_GETITEMTEXT%, %nRow%, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
    
    VarSetCapacity(cRecvBuf, objLV.szreadbuf, 1)
    If ( !DllCall( "ReadProcessMemory", Ptr,objLV.hproc, Ptr,objLV.preadbuf, Ptr,&cRecvBuf, UInt,objLV.szreadbuf
                                      , Ptr,0 ) )
        Throw Exception("objLV.preadbuf: error reading memory", "ReadProcessMemory", "LastError: " A_LastError)
    
    Return StrGet(&cRecvBuf, objLV.szreadbuf, objLV.senc)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_Initialize
; Description ..: Initialize the object containing ListView's related data.
; Parameters ...: sWnd      - Title of the window containing the ListView.
; ..............: szReadBuf - Size of the buffer used for reading the target process memory. It must be capable enough
; ..............:             to hold the longest cell in the ListView.
; ..............: sEnc      - Target ListView's encoding. "CP0" for ANSI, "UTF-8" or "UTF-16" for Unicode.
; Return .......: objLV            - External ListView initialized object with the following keys:
; ..............: objLV.swnd       - Title of the window owning the ListView.
; ..............: objLV.hwnd       - Handle to the window owning the ListView.
; ..............: objLV.hproc      - Handle to the process owning the ListView.
; ..............: objLV.hlv        - Handle to the ListView.
; ..............: objLV.hhdr       - Handle to the header of the ListView.
; ..............: objLV.rows       - Number of rows in the ListView.
; ..............: objLV.cols       - Number of columns in the ListView.
; ..............: objLV.senc       - Encoding used by the process owning the ListView.
; ..............: objLV.pwritebuf  - Address to the buffer used to write the LVITEM message to the target ListView.
; ..............: objLV.szwritebuf - Size of the write buffer.
; ..............: objLV.preadbuf   - Address to the buffer used to read the answer to the message sent.
; ..............: objLV.szreadbuf  - Size of the read buffer.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_Initialize(sWnd, WHICHSysListView:="SysListView321", szReadBuf:=1024, sEnc:="CP0") {
    objLV            := Object()
    objLV.swnd       := sWnd
    objLV.hwnd       := WinExist(sWnd)
    objLV.szwritebuf := (A_OSVersion == "WIN_XP") ? 52 + (A_PtrSize-4)*5 : 60 + (A_PtrSize-4)*7 ; Size of LVITEM
    objLV.szreadbuf  := szReadBuf
    objLV.senc       := sEnc
    
    ControlGet, hLv, Hwnd,, % WHICHSysListView, % "ahk_id " objLV.hwnd
    objLV.hlv := hLv
    
    DllCall( "GetWindowThreadProcessId", Ptr,hLv, PtrP,dwProcessId )
    ; PROCESS_VM_OPERATION = 0x0008, PROCESS_VM_READ = 0x0010, PROCESS_VM_WRITE = 0x0020.
    If ( !(objLV.hproc := DllCall( "OpenProcess", UInt,0x0008|0x0010|0x0020, Int,0, UInt,dwProcessId )) )
        Throw Exception("objLV.hproc: error opening process", "OpenProcess", "LastError: " A_LastError)
    
    ; LVM_GETITEMCOUNT = LVM_FIRST (0x1000) + 4 = 0x1004.
    SendMessage, 0x1004, 0, 0,, % "ahk_id " objLV.hlv
    objLV.rows := ErrorLevel
    
    ; LVM_GETHEADER = LVM_FIRST (0x1000) + 31 = 0x101F.
    SendMessage, 0x101F, 0, 0,, % "ahk_id " objLV.hlv
    objLV.hhdr := ErrorLevel
    
    ; HDM_GETITEMCOUNT = HDM_FIRST (0x1200) + 0 = 0x1200.
    SendMessage, 0x1200, 0, 0,, % "ahk_id " objLV.hhdr
    objLV.cols := ErrorLevel
    
    ; Allocate memory on the target process before returning the object.
    If ( !__ExtListView_AllocateMemory(objLV) )
        Throw Exception("Error allocating memory", "__ExtListView_Initialize", "LastError: " A_LastError)
    
    Return objLV
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_DeInitialize
; Description ..: DeInitialize the object.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_DeInitialize(ByRef objLV) {
    ; Free the previously allocated memory on the target process.
    If ( !__ExtListView_DeAllocateMemory(objLV) )
        Throw Exception("Error deallocating memory", "__ExtListView_DeInitialize", "LastError: " A_LastError)
    DllCall( "CloseHandle", Ptr,objLV.hproc )
    objLV := ""
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_CheckInitObject
; Description ..: Check if the object is still referring to a valid ListView.
; Parameters ...: objLV - External ListView initialized object.
; Return .......: 0 if false, handle of the window containing the ListView if true.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_CheckInitObject(ByRef objLV) {
    Return WinExist("ahk_id " objLV.hwnd)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_AllocateMemory
; Description ..: Allocates memory into the target process.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_AllocateMemory(ByRef objLV) {
    ; MEM_COMMIT = 0x1000, PAGE_READWRITE = 0x4.
    ; hProcess:objLV.hproc
    ; lpAddress: NULL
    ; dwSize:UInt,objLV.szwritebuf
    ; flAllocationType:0x1000 ;MEM_RESET_UNDO ;https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex#MEM_RESET_UNDO
    ; If the function succeeds, the return value is the base address of the allocated region of pages.
    If ( !(objLV.pwritebuf := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szwritebuf, UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    If ( !(objLV.preadbuf  := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szreadbuf,  UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    ; RECT is 16 bytes
    If ( !(objLV.rectbuf  := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,16,  UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    Return 1
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_DeAllocateMemory
; Description ..: Frees previously allocated memory.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_DeAllocateMemory(ByRef objLV) {
    ; MEM_RELEASE = 0x8000.
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("pwritebuf")
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.preadbuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("preadbuf")
    Return 1
}

/* EXAMPLE CODE:

OnExit, QUIT
WINTITLE = Active Directory Users and Computers ahk_class MMCMainFrame
objLV := ExtListView_Initialize(WINTITLE)
HotKey, IfWinActive, %WINTITLE%
HotKey, ^!g, TOGGLESEL
Return

TOGGLESEL:
( ExtListView_CheckInitObject(objLV) ) ? objLV := ExtListView_Initialize(WINTITLE)
ExtListView_ToggleSelection(objLV, 1, 0)
Return

QUIT:
ExtListView_DeInitialize(objLV)
ExitApp

*/

; Focus and clicks last focused row || first row
ExtListView_RestoreFocus(objLV) {
    focusedControl:=ExtListView_getFocusedControl(objLV) 
    ;if not already focused
    if (focusedControl!=objLV.hlv+0) {
        FocusedRow:=ExtListView_GetNextItem(objLV,, 1)
        if (FocusedRow==-1) {
            ; default to first row if no row Focused
            FocusedRow:=0
        }
        ExtListView_EnsureVisible(objLV, FocusedRow)
        ExtListView_ClickRow(objLV, FocusedRow)
    }
}

ExtListView_ClickRow(objLV, Row) { ; just me -> https://www.autohotkey.com/board/topic/86490-click-listview-row/#entry550767
    HLV:=objLV.hlv
    rectbuf:=objLV.rectbuf
    ; HLV : ListView's HWND, Row : 0-based row number

    SendMessage, 0x100E, % Row, % rectbuf,, % "ahk_id " HLV ; LVM_GETITEMRECT
    VarSetCapacity(RECT, 16)
    If ( !DllCall( "ReadProcessMemory", "Ptr",objLV.hproc, "Ptr",objLV.rectbuf, "Ptr",&RECT, UInt,16, UInt,0 ) )
        Throw Exception("objLV.rectbuf: error reading memory", "ReadProcessMemory", "LastError: " A_LastError)

    short1:=NumGet(RECT, 0, "Short")
    short2:=NumGet(RECT, 4, "Short")
    POINT := short1 | (short2 << 16)

    PostMessage, 0x0201, 0, POINT,, % "ahk_id " HLV ; WM_LBUTTONDOWN
    PostMessage, 0x0202, 0, POINT,, % "ahk_id " HLV ; WM_LBUTTONUP
}

ExtListView_EnsureVisible(objLV, Row, fPartialOK:=false) { ; https://www.autohotkey.com/board/topic/8194-double-click-on-listview-selection/#post_id_51730
    ; fPartialOK - A value specifying whether the item must be entirely visible.
    ; If this parameter is TRUE, no scrolling occurs if the item is at least partially visible.
    HLV:=objLV.hlv
    ; PostMessage, 0x1013, Row, fPartialOK,, % "ahk_id " HLV ; LVM_ENSUREVISIBLE 
    SendMessage, 0x1013, Row, fPartialOK,, % "ahk_id " HLV ; LVM_ENSUREVISIBLE 
}

ExtListView_getFocusedControl(objLV) {
    ; https://www.autohotkey.com/boards/viewtopic.php?t=37120
    static vTIDAhk := DllCall("GetCurrentThreadId", "UInt")
    static GuiThreadInfo_Size:=24 + 6*A_PtrSize ;4 + 4 + 6*A_PtrSize + 16
    static offset_hwndFocus := 8 + 1*A_PtrSize
    ;   typedef struct tagGUITHREADINFO {
    ; DWORD cbSize; 0
    ; DWORD flags; 4
    ; HWND hwndActive;    8
    ; HWND hwndFocus;     8 + 1*A_PtrSize
    ; HWND hwndCapture;   8 + 2*A_PtrSize
    ; HWND hwndMenuOwner; 8 + 3*A_PtrSize
    ; HWND hwndMoveSize;  8 + 4*A_PtrSize
    ; HWND hwndCaret;     8 + 5*A_PtrSize
    ; RECT rcCaret;       8 + 6*A_PtrSize
    ;   }
    ; DWORD is Uint
    ; BOOL AttachThreadInput(
    ;   [in] DWORD idAttach,
    ;   [in] DWORD idAttachTo,
    ;   [in] BOOL  fAttach
    ; );
    ; BOOL -> Int
    vTID := DllCall("GetWindowThreadProcessId", "Ptr",objLV.hwnd, "Ptr",0, "UInt")
    

    VarSetCapacity(GuiThreadInfo, GuiThreadInfo_Size, 0)
	; GuiThreadInfo.cbSize = sizeof(GuiThreadInfo);
    NumPut(GuiThreadInfo_Size, GuiThreadInfo,0,"Uint")
    ; GetGuiThreadInfo(vTID, &GuiThreadInfo)
    DllCall("GetGUIThreadInfo", "Uint",vTID, "Ptr",&GuiThreadInfo)

    hwndFocus:=NumGet(GuiThreadInfo, offset_hwndFocus, "Ptr")

    return hwndFocus
}



LVwindowTitle := "Test" ; Adjust as needed

Gui, Font, s10
Gui, Add, ListView, r10, A|B
LV_Add("", "abc"  , "def")
LV_Add("", "ghi"  , "jkl")
Loop, 50
{
	LV_Add("", "test"A_Index, "mike"A_Index)
}
LV_ModifyCol(1, 50), LV_ModifyCol(2, 50)
Gui, Show,, %LVwindowTitle%

lookfor := "test42"

LV            := ExtListView_Initialize(LVwindowTitle)

findText      := lookfor
row           := row(LV, findText)

LV            := ExtListView_EnsureVisible(LVwindowTitle, row, fPartialOK:=false)

;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%
;~ findText      := "jklff"
;~ row           := row(LV, findText, 2)
;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%
;~ findText      := "bbbbbbbbbbbbbb"
;~ row           := row(LV, findText)
;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%

select(LV, lookfor)
;~ select(LV, "jkl", COL := 2)
; select(LV, "hif")


MsgBox, %lookfor% selected - scroll down to see!
Return

select(LV, str, col := 1) {            ; Select a row in a ListView, by string
 (row := row(LV, str, col)) && ExtListView_ToggleSelection(LV, SELECT := True, row - 1)
}

row(LV, str, col := 1) {               ; Find string in a ListView column
 ; https://www.autohotkey.com/boards/viewtopic.php?t=3513
 ; https://www.autohotkey.com/boards/viewtopic.php?p=463971#p463971
 Loop {
  next :=       ExtListView_GetNextItem(LV, row := A_Index - 1)
  pos  := Instr(ExtListView_GetItemText(LV, row, col - 1), str)
 } Until (next < 1 || pos)
 Return pos ? row + 1 : 0              ; Return the row number found, or zero
}

GuiClose:
GuiEscape:
ExitApp


User avatar
boiler
Posts: 16771
Joined: 21 Dec 2014, 02:44

Re: Help with focus\select specific line from SysListView321

Post by boiler » 29 May 2022, 07:18

Regarding this line:

Code: Select all

LV            := ExtListView_EnsureVisible(LVwindowTitle, row, fPartialOK:=false)
LV is the ListView object that was assigned when you initialized the library, assuming that was done correctly. You pass that to the function; you don’t overwrite it with the return value of this function. This function apparently doesn’t return any value anyway, so don’t assign the return value to anything.

Where the function definition shows fpartialok:=false, that means the default value is false and you don’t need to send anything if you want to use the default. And when you pass it as fpartialok:=false, you are needlessly creating a global variable named fpartialok and assigning false to it.

Your function call should be:

Code: Select all

ExtListView_EnsureVisible(LV, row)

User avatar
Tomer
Posts: 366
Joined: 21 Aug 2016, 05:11

Re: Help with focus\select specific line from SysListView321

Post by Tomer » 29 May 2022, 08:19

@boiler
@mikeyww

I managed to get it work thanks to your help - thank you :clap:

Please take a look you may can imporve this since its sometimes freezes +
one more issue,
need help with unselect all the rows before selecting the row name "test42" ? (F1 key to select),
so only 1 row selected\focused at same time

Code: Select all

; https://www.autohotkey.com/boards/viewtopic.php?t=3513
; ----------------------------------------------------------------------------------------------------------------------
; Name .........: ExtListView library
; Description ..: Collection of functions dealing with the ListViews of external processes.
; AHK Version ..: AHK_L 1.1.13.01 x32/64 ANSI/Unicode
; Author .......: Cyruz - http://ciroprincipe.info
; License ......: WTFPL - http://www.wtfpl.net/txt/copying/
; Changelog ....: May  18, 2013 - v0.1 - First revision.
; ..............: Jun. 28, 2013 - v0.2 - Added resizable buffer option.
; ..............: Feb. 04, 2014 - v0.3 - Unicode and x64 compatibility.
; ..............: Apr. 10, 2014 - v1.0 - Code refactoring. Added encoding option and simple error management.
; ..............: May  04, 2014 - v1.1 - Detached the handles and memory allocation code.
; ..............: May  05, 2014 - v1.2 - Created ExtListView_GetAllItems and ExtListView_ToggleSelection functions.
; ..............: May  06, 2014 - v2.0 - Complete rewrite of the library. Code more modular and updateable. Separated 
; ..............:                        code for De/Initialization, GetNextItem and GetItemText.
; ..............: Jul  24, 2017 - v2.1 - Fixed LVITEM size issue.
; ----------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetSingleItem
; Description ..: Get the first item with the desired state.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001 ;The item has the focus, so it is surrounded by a standard focus rectangle. Although more than one item may be selected, only one item can have the focus.
; ..............:          LVNI_SELECTED    - 0x0002 ;The item is selected. The appearance of a selected item depends on whether it has the focus and also on the system colors used for selection.
; ..............:          LVNI_CUT         - 0x0004 ;The item is marked for a cut-and-paste operation.
; ..............:          LVNI_DROPHILITED - 0x0008 ;The item is highlighted as a drag-and-drop target.
; ..............: nCol   - Column of the desired item (0-based index).
; Info .........: For more info on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Single item as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetSingleItem(ByRef objLV, sState, nCol) {
    Try {
        
        If ( (nRow  := ExtListView_GetNextItem(objLV, -1, sState)) != -1 )
            sItem := ExtListView_GetItemText(objLV, nRow, nCol)
        
    } Catch e
      Throw e
      
    Return (sItem) ? sItem : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetAllItems
; Description ..: Get all items that share the same status on the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: For more infor on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Multidimensional array containing ListView's items. Eg: array[row][column] := "SomeString".
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetAllItems(ByRef objLV, sState:=0x0000) {
    Try {
        
        nRow := -1, objList := []
        Loop
        {
            If ( (nRow := ExtListView_GetNextItem(objLV, nRow, sState)) == -1 )
                Break
            x := A_Index, objList[x] := []
            Loop % objLV.cols
                objList[x][A_Index] := ExtListView_GetItemText(objLV, nRow, A_Index-1)
        }
        
    } Catch e
      Throw e
      
    Return ( objList.MaxIndex() ) ? objList : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_ToggleSelection
; Description ..: Select/deselect items in the target ListView.
; Parameters ...: objLV   - External ListView initialized object.
; ..............: bSelect - 1 for selection, 0 for deselection.
; ..............: nItem   - -1 for all items or "n" (0-based) for a specific ListView item.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_ToggleSelection(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0002 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED = 0x0002 or 0x0000 (reset mask).
    NumPut( 0x0002,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.
    
    If ( !DllCall( "WriteProcessMemory", "Ptr",objLV.hproc, "Ptr",objLV.pwritebuf, "Ptr",&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv ;LVM_SETITEMSTATE
    ;#####, this works because it's reading from it's OWN MEMORY objLV.pwritebuf
}
ExtListView_ToggleFocusAndSelection(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0003 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED =  0x0002 or 0x0000 (reset mask).
    NumPut( 0x0003,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}
ExtListView_ToggleFocus(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0001 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED =  0x0002 or 0x0000 (reset mask).
    NumPut( 0x0001,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetNextItem
; Description ..: Get the next item in the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: nRow   - Row where to start the search for the next item (0-based index).
; ..............: lParam - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: LVM_GETNEXTITEM - http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetNextItem(ByRef objLV, nRow:=-1, lParam:=0x0000) {
    ; LVM_GETNEXTITEM = LVM_FIRST (0x1000) + 12 = 0x100C.
    SendMessage, 0x100C, %nRow%, %lParam%,, % "ahk_id " objLV.hlv
    Return ErrorLevel << 32 >> 32
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetItemText
; Description ..: Get the text of the desired item.
; Parameters ...: objLV - External ListView initialized object.
; ..............: nRow  - Row of the desired item (0-based index).
; ..............: nCol  - Column of the desired item (0-based index).
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetItemText(ByRef objLV, nRow, nCol) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0001,          LVITEM, 0                          ) ; mask = LVIF_TEXT = 0x0001.
    NumPut( nRow,            LVITEM, 4                          ) ; iItem = Row to retrieve (0 = 1st row).
    NumPut( nCol,            LVITEM, 8                          ) ; iSubItem = The column index of the item to retrieve.
    NumPut( objLV.preadbuf,  LVITEM, 20 + (A_PtrSize - 4)       ) ; pszText = Pointer to item text string.
    NumPut( objLV.szreadbuf, LVITEM, 20 + ((A_PtrSize * 2) - 4) ) ; cchTextMax = Number of TCHARs in the buffer.
    
    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,objLV.szwritebuf
                                       , UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    
    ; LVM_GETITEMTEXTA = LVM_FIRST (0x1000) + 45  = 0x102D.
    ; LVM_GETITEMTEXTW = LVM_FIRST (0x1000) + 115 = 0x1073.
    LVM_GETITEMTEXT := (objLV.senc == "UTF-8" || objLV.senc == "UTF-16") ? 0x1073 : 0x102D
    SendMessage, %LVM_GETITEMTEXT%, %nRow%, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
    
    VarSetCapacity(cRecvBuf, objLV.szreadbuf, 1)
    If ( !DllCall( "ReadProcessMemory", Ptr,objLV.hproc, Ptr,objLV.preadbuf, Ptr,&cRecvBuf, UInt,objLV.szreadbuf
                                      , Ptr,0 ) )
        Throw Exception("objLV.preadbuf: error reading memory", "ReadProcessMemory", "LastError: " A_LastError)
    
    Return StrGet(&cRecvBuf, objLV.szreadbuf, objLV.senc)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_Initialize
; Description ..: Initialize the object containing ListView's related data.
; Parameters ...: sWnd      - Title of the window containing the ListView.
; ..............: szReadBuf - Size of the buffer used for reading the target process memory. It must be capable enough
; ..............:             to hold the longest cell in the ListView.
; ..............: sEnc      - Target ListView's encoding. "CP0" for ANSI, "UTF-8" or "UTF-16" for Unicode.
; Return .......: objLV            - External ListView initialized object with the following keys:
; ..............: objLV.swnd       - Title of the window owning the ListView.
; ..............: objLV.hwnd       - Handle to the window owning the ListView.
; ..............: objLV.hproc      - Handle to the process owning the ListView.
; ..............: objLV.hlv        - Handle to the ListView.
; ..............: objLV.hhdr       - Handle to the header of the ListView.
; ..............: objLV.rows       - Number of rows in the ListView.
; ..............: objLV.cols       - Number of columns in the ListView.
; ..............: objLV.senc       - Encoding used by the process owning the ListView.
; ..............: objLV.pwritebuf  - Address to the buffer used to write the LVITEM message to the target ListView.
; ..............: objLV.szwritebuf - Size of the write buffer.
; ..............: objLV.preadbuf   - Address to the buffer used to read the answer to the message sent.
; ..............: objLV.szreadbuf  - Size of the read buffer.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_Initialize(sWnd, WHICHSysListView:="SysListView321", szReadBuf:=1024, sEnc:="CP0") {
    objLV            := Object()
    objLV.swnd       := sWnd
    objLV.hwnd       := WinExist(sWnd)
    objLV.szwritebuf := (A_OSVersion == "WIN_XP") ? 52 + (A_PtrSize-4)*5 : 60 + (A_PtrSize-4)*7 ; Size of LVITEM
    objLV.szreadbuf  := szReadBuf
    objLV.senc       := sEnc
    
    ControlGet, hLv, Hwnd,, % WHICHSysListView, % "ahk_id " objLV.hwnd
    objLV.hlv := hLv
    
    DllCall( "GetWindowThreadProcessId", Ptr,hLv, PtrP,dwProcessId )
    ; PROCESS_VM_OPERATION = 0x0008, PROCESS_VM_READ = 0x0010, PROCESS_VM_WRITE = 0x0020.
    If ( !(objLV.hproc := DllCall( "OpenProcess", UInt,0x0008|0x0010|0x0020, Int,0, UInt,dwProcessId )) )
        Throw Exception("objLV.hproc: error opening process", "OpenProcess", "LastError: " A_LastError)
    
    ; LVM_GETITEMCOUNT = LVM_FIRST (0x1000) + 4 = 0x1004.
    SendMessage, 0x1004, 0, 0,, % "ahk_id " objLV.hlv
    objLV.rows := ErrorLevel
    
    ; LVM_GETHEADER = LVM_FIRST (0x1000) + 31 = 0x101F.
    SendMessage, 0x101F, 0, 0,, % "ahk_id " objLV.hlv
    objLV.hhdr := ErrorLevel
    
    ; HDM_GETITEMCOUNT = HDM_FIRST (0x1200) + 0 = 0x1200.
    SendMessage, 0x1200, 0, 0,, % "ahk_id " objLV.hhdr
    objLV.cols := ErrorLevel
    
    ; Allocate memory on the target process before returning the object.
    If ( !__ExtListView_AllocateMemory(objLV) )
        Throw Exception("Error allocating memory", "__ExtListView_Initialize", "LastError: " A_LastError)
    
    Return objLV
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_DeInitialize
; Description ..: DeInitialize the object.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_DeInitialize(ByRef objLV) {
    ; Free the previously allocated memory on the target process.
    If ( !__ExtListView_DeAllocateMemory(objLV) )
        Throw Exception("Error deallocating memory", "__ExtListView_DeInitialize", "LastError: " A_LastError)
    DllCall( "CloseHandle", Ptr,objLV.hproc )
    objLV := ""
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_CheckInitObject
; Description ..: Check if the object is still referring to a valid ListView.
; Parameters ...: objLV - External ListView initialized object.
; Return .......: 0 if false, handle of the window containing the ListView if true.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_CheckInitObject(ByRef objLV) {
    Return WinExist("ahk_id " objLV.hwnd)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_AllocateMemory
; Description ..: Allocates memory into the target process.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_AllocateMemory(ByRef objLV) {
    ; MEM_COMMIT = 0x1000, PAGE_READWRITE = 0x4.
    ; hProcess:objLV.hproc
    ; lpAddress: NULL
    ; dwSize:UInt,objLV.szwritebuf
    ; flAllocationType:0x1000 ;MEM_RESET_UNDO ;https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex#MEM_RESET_UNDO
    ; If the function succeeds, the return value is the base address of the allocated region of pages.
    If ( !(objLV.pwritebuf := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szwritebuf, UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    If ( !(objLV.preadbuf  := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szreadbuf,  UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    ; RECT is 16 bytes
    If ( !(objLV.rectbuf  := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,16,  UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    Return 1
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_DeAllocateMemory
; Description ..: Frees previously allocated memory.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_DeAllocateMemory(ByRef objLV) {
    ; MEM_RELEASE = 0x8000.
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("pwritebuf")
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.preadbuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("preadbuf")
    Return 1
}

/* EXAMPLE CODE:

OnExit, QUIT
WINTITLE = Active Directory Users and Computers ahk_class MMCMainFrame
objLV := ExtListView_Initialize(WINTITLE)
HotKey, IfWinActive, %WINTITLE%
HotKey, ^!g, TOGGLESEL
Return

TOGGLESEL:
( ExtListView_CheckInitObject(objLV) ) ? objLV := ExtListView_Initialize(WINTITLE)
ExtListView_ToggleSelection(objLV, 1, 0)
Return

QUIT:
ExtListView_DeInitialize(objLV)
ExitApp

*/

; Focus and clicks last focused row || first row
ExtListView_RestoreFocus(objLV) {
    focusedControl:=ExtListView_getFocusedControl(objLV) 
    ;if not already focused
    if (focusedControl!=objLV.hlv+0) {
        FocusedRow:=ExtListView_GetNextItem(objLV,, 1)
        if (FocusedRow==-1) {
            ; default to first row if no row Focused
            FocusedRow:=0
        }
        ExtListView_EnsureVisible(objLV, FocusedRow)
        ExtListView_ClickRow(objLV, FocusedRow)
    }
}

ExtListView_ClickRow(objLV, Row) { ; just me -> https://www.autohotkey.com/board/topic/86490-click-listview-row/#entry550767
    HLV:=objLV.hlv
    rectbuf:=objLV.rectbuf
    ; HLV : ListView's HWND, Row : 0-based row number

    SendMessage, 0x100E, % Row, % rectbuf,, % "ahk_id " HLV ; LVM_GETITEMRECT
    VarSetCapacity(RECT, 16)
    If ( !DllCall( "ReadProcessMemory", "Ptr",objLV.hproc, "Ptr",objLV.rectbuf, "Ptr",&RECT, UInt,16, UInt,0 ) )
        Throw Exception("objLV.rectbuf: error reading memory", "ReadProcessMemory", "LastError: " A_LastError)

    short1:=NumGet(RECT, 0, "Short")
    short2:=NumGet(RECT, 4, "Short")
    POINT := short1 | (short2 << 16)

    PostMessage, 0x0201, 0, POINT,, % "ahk_id " HLV ; WM_LBUTTONDOWN
    PostMessage, 0x0202, 0, POINT,, % "ahk_id " HLV ; WM_LBUTTONUP
}

ExtListView_EnsureVisible(objLV, Row, fPartialOK:=false) { ; https://www.autohotkey.com/board/topic/8194-double-click-on-listview-selection/#post_id_51730
    ; fPartialOK - A value specifying whether the item must be entirely visible.
    ; If this parameter is TRUE, no scrolling occurs if the item is at least partially visible.
    HLV:=objLV.hlv
    ; PostMessage, 0x1013, Row, fPartialOK,, % "ahk_id " HLV ; LVM_ENSUREVISIBLE 
    SendMessage, 0x1013, Row, fPartialOK,, % "ahk_id " HLV ; LVM_ENSUREVISIBLE 
}

ExtListView_getFocusedControl(objLV) {
    ; https://www.autohotkey.com/boards/viewtopic.php?t=37120
    static vTIDAhk := DllCall("GetCurrentThreadId", "UInt")
    static GuiThreadInfo_Size:=24 + 6*A_PtrSize ;4 + 4 + 6*A_PtrSize + 16
    static offset_hwndFocus := 8 + 1*A_PtrSize
    ;   typedef struct tagGUITHREADINFO {
    ; DWORD cbSize; 0
    ; DWORD flags; 4
    ; HWND hwndActive;    8
    ; HWND hwndFocus;     8 + 1*A_PtrSize
    ; HWND hwndCapture;   8 + 2*A_PtrSize
    ; HWND hwndMenuOwner; 8 + 3*A_PtrSize
    ; HWND hwndMoveSize;  8 + 4*A_PtrSize
    ; HWND hwndCaret;     8 + 5*A_PtrSize
    ; RECT rcCaret;       8 + 6*A_PtrSize
    ;   }
    ; DWORD is Uint
    ; BOOL AttachThreadInput(
    ;   [in] DWORD idAttach,
    ;   [in] DWORD idAttachTo,
    ;   [in] BOOL  fAttach
    ; );
    ; BOOL -> Int
    vTID := DllCall("GetWindowThreadProcessId", "Ptr",objLV.hwnd, "Ptr",0, "UInt")
    

    VarSetCapacity(GuiThreadInfo, GuiThreadInfo_Size, 0)
	; GuiThreadInfo.cbSize = sizeof(GuiThreadInfo);
    NumPut(GuiThreadInfo_Size, GuiThreadInfo,0,"Uint")
    ; GetGuiThreadInfo(vTID, &GuiThreadInfo)
    DllCall("GetGUIThreadInfo", "Uint",vTID, "Ptr",&GuiThreadInfo)

    hwndFocus:=NumGet(GuiThreadInfo, offset_hwndFocus, "Ptr")

    return hwndFocus
}



LVwindowTitle := "Test" ; Adjust as needed

Gui, Font, s10
Gui, Add, ListView, r10, A|B
LV_Add("", "abc"  , "def")
LV_Add("", "ghi"  , "jkl")
Loop, 50
{
	LV_Add("", "test"A_Index, "mike"A_Index)
}
LV_ModifyCol(1, 50), LV_ModifyCol(2, 50)
Gui, Show,, %LVwindowTitle%

lookfor := "test42"

LV            := ExtListView_Initialize(LVwindowTitle)

;~ findText      := lookfor
;~ row           := row(LV, findText)
;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%
;~ findText      := "jklff"
;~ row           := row(LV, findText, 2)
;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%
;~ findText      := "bbbbbbbbbbbbbb"
;~ row           := row(LV, findText)
;~ MsgBox, 64, Text, Text: %findText%`n`nRow: %row%

F1::
select(LV, lookfor)
;~ select(LV, "jkl", COL := 2)
; select(LV, "hif")

Return

select(LV, str, col := 1) {            ; Select a row in a ListView, by string
 (row := row(LV, str, col)) && ExtListView_ToggleSelection(LV, SELECT := True, row - 1)
 (row := row(LV, str, col)) && ExtListView_EnsureVisible(LV, Row)
}

row(LV, str, col := 1) {               ; Find string in a ListView column
 ; https://www.autohotkey.com/boards/viewtopic.php?t=3513
 ; https://www.autohotkey.com/boards/viewtopic.php?p=463971#p463971
 Loop {
  next :=       ExtListView_GetNextItem(LV, row := A_Index - 1)
  pos  := Instr(ExtListView_GetItemText(LV, row, col - 1), str)
 } Until (next < 1 || pos)
 Return pos ? row + 1 : 0              ; Return the row number found, or zero
}

GuiClose:
GuiEscape:
ExitApp



MrDoge
Posts: 151
Joined: 27 Apr 2020, 21:29

Re: Help with focus\select specific line from SysListView321

Post by MrDoge » 29 May 2022, 14:40

thanks for posting full code so I can run it, see what's not working
need help with unselect all the rows before selecting the row name "test42" ? (F1 key to select),
so only 1 row selected\focused at same time
once I saw LV_Add("", "test" A_Index, "mike" A_Index), I was like : ayt, this is runnable/reproducible code, not same random listview(on your computer) that I don't have access to, that I can't test
I didn't even think of making a listview myself, I was thinking of finding a listview to test this on, but this is better(you can set the text, you know the encoding, you know the hwnd)
I guess I did not want to create or find tests, I just want to write code to pass a test : (I only write this part if I need to..) (oh, to pass a "test", like : recreate this Gui(same appearance))

Code: Select all

LVwindowTitle := "Test" ; Adjust as needed

Gui, Font, s10
Gui, Add, ListView, r10, A|B
LV_Add("", "abc"  , "def")
LV_Add("", "ghi"  , "jkl")
Loop, 50
{
	LV_Add("", "test"A_Index, "mike"A_Index)
}
LV_ModifyCol(1, 50), LV_ModifyCol(2, 50)
Gui, Show,, %LVwindowTitle%
I put your code at the top

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance force
ListLines Off
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetBatchLines -1
#KeyHistory 0

LVwindowTitle := "Test" ; Adjust as needed

Gui, Font, s10
Gui, Add, ListView, r10, A|B
LV_Add("", "abc"  , "def")
LV_Add("", "ghi"  , "jkl")
Loop, 50
{
	LV_Add("", "test" A_Index, "mike" A_Index)
}
LV_ModifyCol(1, 50), LV_ModifyCol(2, 50)
Gui, Show,, %LVwindowTitle%

objLV := ExtListView_Initialize(LVwindowTitle)

f1::
row:=ExtListView_findRowWithString(objLV, "test42")
if (row != -1) {
    ExtListView_EnsureVisible(objLV, row)
    ExtListView_ClickRow(objLV, row)
}

Return

ExtListView_findRowWithString(objLV, str, col:=0) {
    row:=0
    while (row < objLV.rows) {
        text:=ExtListView_GetItemText(objLV, row, col)
        if (text == str) { ;copy this function if you want case insensitive
            return row
        }
        row++
    }
    return -1
}

GuiClose:
GuiEscape:
ExitApp

f3::Exitapp

; https://www.autohotkey.com/boards/viewtopic.php?t=3513
; ----------------------------------------------------------------------------------------------------------------------
; Name .........: ExtListView library
; Description ..: Collection of functions dealing with the ListViews of external processes.
; AHK Version ..: AHK_L 1.1.13.01 x32/64 ANSI/Unicode
; Author .......: Cyruz - http://ciroprincipe.info
; License ......: WTFPL - http://www.wtfpl.net/txt/copying/
; Changelog ....: May  18, 2013 - v0.1 - First revision.
; ..............: Jun. 28, 2013 - v0.2 - Added resizable buffer option.
; ..............: Feb. 04, 2014 - v0.3 - Unicode and x64 compatibility.
; ..............: Apr. 10, 2014 - v1.0 - Code refactoring. Added encoding option and simple error management.
; ..............: May  04, 2014 - v1.1 - Detached the handles and memory allocation code.
; ..............: May  05, 2014 - v1.2 - Created ExtListView_GetAllItems and ExtListView_ToggleSelection functions.
; ..............: May  06, 2014 - v2.0 - Complete rewrite of the library. Code more modular and updateable. Separated
; ..............:                        code for De/Initialization, GetNextItem and GetItemText.
; ..............: Jul  24, 2017 - v2.1 - Fixed LVITEM size issue.
; ----------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetSingleItem
; Description ..: Get the first item with the desired state.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001 ;The item has the focus, so it is surrounded by a standard focus rectangle. Although more than one item may be selected, only one item can have the focus.
; ..............:          LVNI_SELECTED    - 0x0002 ;The item is selected. The appearance of a selected item depends on whether it has the focus and also on the system colors used for selection.
; ..............:          LVNI_CUT         - 0x0004 ;The item is marked for a cut-and-paste operation.
; ..............:          LVNI_DROPHILITED - 0x0008 ;The item is highlighted as a drag-and-drop target.
; ..............: nCol   - Column of the desired item (0-based index).
; Info .........: For more info on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Single item as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetSingleItem(ByRef objLV, sState, nCol) {
    Try {

        If ( (nRow  := ExtListView_GetNextItem(objLV, -1, sState)) != -1 )
            sItem := ExtListView_GetItemText(objLV, nRow, nCol)

    } Catch e
      Throw e

    Return (sItem) ? sItem : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetAllItems
; Description ..: Get all items that share the same status on the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: sState - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: For more infor on the sState parameter have a look at the MSDN docs for the LVM_GETNEXTITEM message:
; ..............: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Multidimensional array containing ListView's items. Eg: array[row][column] := "SomeString".
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetAllItems(ByRef objLV, sState:=0x0000) {
    Try {

        nRow := -1, objList := []
        Loop
        {
            If ( (nRow := ExtListView_GetNextItem(objLV, nRow, sState)) == -1 )
                Break
            x := A_Index, objList[x] := []
            Loop % objLV.cols
                objList[x][A_Index] := ExtListView_GetItemText(objLV, nRow, A_Index-1)
        }

    } Catch e
      Throw e

    Return ( objList.MaxIndex() ) ? objList : 0
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_ToggleSelection
; Description ..: Select/deselect items in the target ListView.
; Parameters ...: objLV   - External ListView initialized object.
; ..............: bSelect - 1 for selection, 0 for deselection.
; ..............: nItem   - -1 for all items or "n" (0-based) for a specific ListView item.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_ToggleSelection(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0002 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED = 0x0002 or 0x0000 (reset mask).
    NumPut( 0x0002,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.

    If ( !DllCall( "WriteProcessMemory", "Ptr",objLV.hproc, "Ptr",objLV.pwritebuf, "Ptr",&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv ;LVM_SETITEMSTATE
    ;#####, this works because it's reading from it's OWN MEMORY objLV.pwritebuf
}
ExtListView_ToggleFocusAndSelection(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0003 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED =  0x0002 or 0x0000 (reset mask).
    NumPut( 0x0003,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.

    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}
ExtListView_ToggleFocus(ByRef objLV, bSelect:=1, nItem:=-1) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0008,                      LVITEM, 0  ) ; mask = LVIF_STATE = 0x0008.
    NumPut( nItem,                       LVITEM, 4  ) ; iItem.
    NumPut( 0,                           LVITEM, 8  ) ; iSubItem.
    NumPut( (bSelect) ? 0x0001 : 0x0000, LVITEM, 12 ) ; state = LVIS_SELECTED =  0x0002 or 0x0000 (reset mask).
    NumPut( 0x0001,                      LVITEM, 16 ) ; stateMask = LVIS_SELECTED = 0x0002.

    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,20, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetNextItem
; Description ..: Get the next item in the target ListView.
; Parameters ...: objLV  - External ListView initialized object.
; ..............: nRow   - Row where to start the search for the next item (0-based index).
; ..............: lParam - Status of the searched item. Common statuses are:
; ..............:          LVNI_ALL         - 0x0000
; ..............:          LVNI_FOCUSED     - 0x0001
; ..............:          LVNI_SELECTED    - 0x0002
; ..............:          LVNI_CUT         - 0x0004
; ..............:          LVNI_DROPHILITED - 0x0008
; Info .........: LVM_GETNEXTITEM - http://msdn.microsoft.com/en-us/library/windows/desktop/bb761057%28v=vs.85%29.aspx
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetNextItem(ByRef objLV, nRow:=-1, lParam:=0x0000) {
    ; LVM_GETNEXTITEM = LVM_FIRST (0x1000) + 12 = 0x100C.
    SendMessage, 0x100C, %nRow%, %lParam%,, % "ahk_id " objLV.hlv
    Return ErrorLevel << 32 >> 32
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetItemText
; Description ..: Get the text of the desired item.
; Parameters ...: objLV - External ListView initialized object.
; ..............: nRow  - Row of the desired item (0-based index).
; ..............: nCol  - Column of the desired item (0-based index).
; Return .......: Item content as a string.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_GetItemText(ByRef objLV, nRow, nCol) {
    VarSetCapacity( LVITEM, objLV.szwritebuf, 0 )
    NumPut( 0x0001,          LVITEM, 0                          ) ; mask = LVIF_TEXT = 0x0001.
    NumPut( nRow,            LVITEM, 4                          ) ; iItem = Row to retrieve (0 = 1st row).
    NumPut( nCol,            LVITEM, 8                          ) ; iSubItem = The column index of the item to retrieve.
    NumPut( objLV.preadbuf,  LVITEM, 20 + (A_PtrSize - 4)       ) ; pszText = Pointer to item text string.
    NumPut( objLV.szreadbuf, LVITEM, 20 + ((A_PtrSize * 2) - 4) ) ; cchTextMax = Number of TCHARs in the buffer.

    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, Ptr,&LVITEM, UInt,objLV.szwritebuf
                                       , UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)

    ; LVM_GETITEMTEXTA = LVM_FIRST (0x1000) + 45  = 0x102D.
    ; LVM_GETITEMTEXTW = LVM_FIRST (0x1000) + 115 = 0x1073.
    LVM_GETITEMTEXT := (objLV.senc == "UTF-8" || objLV.senc == "UTF-16") ? 0x1073 : 0x102D
    SendMessage, %LVM_GETITEMTEXT%, %nRow%, % objLV.pwritebuf,, % "ahk_id " objLV.hlv

    VarSetCapacity(cRecvBuf, objLV.szreadbuf, 1)
    If ( !DllCall( "ReadProcessMemory", Ptr,objLV.hproc, Ptr,objLV.preadbuf, Ptr,&cRecvBuf, UInt,objLV.szreadbuf
                                      , Ptr,0 ) )
        Throw Exception("objLV.preadbuf: error reading memory", "ReadProcessMemory", "LastError: " A_LastError)

    Return StrGet(&cRecvBuf, objLV.szreadbuf, objLV.senc)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_Initialize
; Description ..: Initialize the object containing ListView's related data.
; Parameters ...: sWnd      - Title of the window containing the ListView.
; ..............: szReadBuf - Size of the buffer used for reading the target process memory. It must be capable enough
; ..............:             to hold the longest cell in the ListView.
; ..............: sEnc      - Target ListView's encoding. "CP0" for ANSI, "UTF-8" or "UTF-16" for Unicode.
; Return .......: objLV            - External ListView initialized object with the following keys:
; ..............: objLV.swnd       - Title of the window owning the ListView.
; ..............: objLV.hwnd       - Handle to the window owning the ListView.
; ..............: objLV.hproc      - Handle to the process owning the ListView.
; ..............: objLV.hlv        - Handle to the ListView.
; ..............: objLV.hhdr       - Handle to the header of the ListView.
; ..............: objLV.rows       - Number of rows in the ListView.
; ..............: objLV.cols       - Number of columns in the ListView.
; ..............: objLV.senc       - Encoding used by the process owning the ListView.
; ..............: objLV.pwritebuf  - Address to the buffer used to write the LVITEM message to the target ListView.
; ..............: objLV.szwritebuf - Size of the write buffer.
; ..............: objLV.preadbuf   - Address to the buffer used to read the answer to the message sent.
; ..............: objLV.szreadbuf  - Size of the read buffer.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_Initialize(sWnd, WHICHSysListView:="SysListView321", szReadBuf:=1024, sEnc:="CP0") {
    objLV            := Object()
    objLV.swnd       := sWnd
    objLV.hwnd       := WinExist(sWnd)
    objLV.szwritebuf := (A_OSVersion == "WIN_XP") ? 52 + (A_PtrSize-4)*5 : 60 + (A_PtrSize-4)*7 ; Size of LVITEM
    objLV.szreadbuf  := szReadBuf
    objLV.senc       := sEnc

    ControlGet, hLv, Hwnd,, % WHICHSysListView, % "ahk_id " objLV.hwnd
    objLV.hlv := hLv

    DllCall( "GetWindowThreadProcessId", Ptr,hLv, PtrP,dwProcessId )
    ; PROCESS_VM_OPERATION = 0x0008, PROCESS_VM_READ = 0x0010, PROCESS_VM_WRITE = 0x0020.
    If ( !(objLV.hproc := DllCall( "OpenProcess", UInt,0x0008|0x0010|0x0020, Int,0, UInt,dwProcessId )) )
        Throw Exception("objLV.hproc: error opening process", "OpenProcess", "LastError: " A_LastError)

    ; LVM_GETITEMCOUNT = LVM_FIRST (0x1000) + 4 = 0x1004.
    SendMessage, 0x1004, 0, 0,, % "ahk_id " objLV.hlv
    objLV.rows := ErrorLevel

    ; LVM_GETHEADER = LVM_FIRST (0x1000) + 31 = 0x101F.
    SendMessage, 0x101F, 0, 0,, % "ahk_id " objLV.hlv
    objLV.hhdr := ErrorLevel

    ; HDM_GETITEMCOUNT = HDM_FIRST (0x1200) + 0 = 0x1200.
    SendMessage, 0x1200, 0, 0,, % "ahk_id " objLV.hhdr
    objLV.cols := ErrorLevel

    ; Allocate memory on the target process before returning the object.
    If ( !__ExtListView_AllocateMemory(objLV) )
        Throw Exception("Error allocating memory", "__ExtListView_Initialize", "LastError: " A_LastError)

    Return objLV
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_DeInitialize
; Description ..: DeInitialize the object.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_DeInitialize(ByRef objLV) {
    ; Free the previously allocated memory on the target process.
    If ( !__ExtListView_DeAllocateMemory(objLV) )
        Throw Exception("Error deallocating memory", "__ExtListView_DeInitialize", "LastError: " A_LastError)
    DllCall( "CloseHandle", Ptr,objLV.hproc )
    objLV := ""
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_CheckInitObject
; Description ..: Check if the object is still referring to a valid ListView.
; Parameters ...: objLV - External ListView initialized object.
; Return .......: 0 if false, handle of the window containing the ListView if true.
; ----------------------------------------------------------------------------------------------------------------------
ExtListView_CheckInitObject(ByRef objLV) {
    Return WinExist("ahk_id " objLV.hwnd)
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_AllocateMemory
; Description ..: Allocates memory into the target process.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_AllocateMemory(ByRef objLV) {
    ; MEM_COMMIT = 0x1000, PAGE_READWRITE = 0x4.
    ; hProcess:objLV.hproc
    ; lpAddress: NULL
    ; dwSize:UInt,objLV.szwritebuf
    ; flAllocationType:0x1000 ;MEM_RESET_UNDO ;https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex#MEM_RESET_UNDO
    ; If the function succeeds, the return value is the base address of the allocated region of pages.
    If ( !(objLV.pwritebuf := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szwritebuf, UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    If ( !(objLV.preadbuf  := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,objLV.szreadbuf,  UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    ; RECT is 16 bytes
    If ( !(objLV.rectbuf  := DllCall( "VirtualAllocEx", Ptr,objLV.hproc, Ptr,0, UInt,16,  UInt,0x1000
                                                       , UInt,0x4 )) )
        Return 0
    Return 1
}

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: __ExtListView_DeAllocateMemory
; Description ..: Frees previously allocated memory.
; Parameters ...: objLV - External ListView initialized object.
; ----------------------------------------------------------------------------------------------------------------------
__ExtListView_DeAllocateMemory(ByRef objLV) {
    ; MEM_RELEASE = 0x8000.
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.pwritebuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("pwritebuf")
    If ( !DllCall( "VirtualFreeEx", Ptr,objLV.hproc, Ptr,objLV.preadbuf, UInt,0, UInt,0x8000 ) )
        Return 0
    objLV.Remove("preadbuf")
    Return 1
}

/* EXAMPLE CODE:

OnExit, QUIT
WINTITLE = Active Directory Users and Computers ahk_class MMCMainFrame
objLV := ExtListView_Initialize(WINTITLE)
HotKey, IfWinActive, %WINTITLE%
HotKey, ^!g, TOGGLESEL
Return

TOGGLESEL:
( ExtListView_CheckInitObject(objLV) ) ? objLV := ExtListView_Initialize(WINTITLE)
ExtListView_ToggleSelection(objLV, 1, 0)
Return

QUIT:
ExtListView_DeInitialize(objLV)
ExitApp

*/

; Focus and clicks last focused row || first row
ExtListView_RestoreFocus(objLV) {
    focusedControl:=ExtListView_getFocusedControl(objLV)
    ;if not already focused
    if (focusedControl!=objLV.hlv+0) {
        FocusedRow:=ExtListView_GetNextItem(objLV,, 1)
        if (FocusedRow==-1) {
            ; default to first row if no row Focused
            FocusedRow:=0
        }
        ExtListView_EnsureVisible(objLV, FocusedRow)
        ExtListView_ClickRow(objLV, FocusedRow)
    }
}

ExtListView_ClickRow(objLV, Row) { ; just me -> https://www.autohotkey.com/board/topic/86490-click-listview-row/#entry550767
    HLV:=objLV.hlv
    rectbuf:=objLV.rectbuf
    ; HLV : ListView's HWND, Row : 0-based row number

    SendMessage, 0x100E, % Row, % rectbuf,, % "ahk_id " HLV ; LVM_GETITEMRECT
    VarSetCapacity(RECT, 16)
    If ( !DllCall( "ReadProcessMemory", "Ptr",objLV.hproc, "Ptr",objLV.rectbuf, "Ptr",&RECT, UInt,16, UInt,0 ) )
        Throw Exception("objLV.rectbuf: error reading memory", "ReadProcessMemory", "LastError: " A_LastError)

    short1:=NumGet(RECT, 0, "Short")
    short2:=NumGet(RECT, 4, "Short")
    POINT := short1 | (short2 << 16)

    PostMessage, 0x0201, 0, POINT,, % "ahk_id " HLV ; WM_LBUTTONDOWN
    PostMessage, 0x0202, 0, POINT,, % "ahk_id " HLV ; WM_LBUTTONUP
}

ExtListView_EnsureVisible(objLV, Row, fPartialOK:=false) { ; https://www.autohotkey.com/board/topic/8194-double-click-on-listview-selection/#post_id_51730
    ; fPartialOK - A value specifying whether the item must be entirely visible.
    ; If this parameter is TRUE, no scrolling occurs if the item is at least partially visible.
    HLV:=objLV.hlv
    ; PostMessage, 0x1013, Row, fPartialOK,, % "ahk_id " HLV ; LVM_ENSUREVISIBLE
    SendMessage, 0x1013, Row, fPartialOK,, % "ahk_id " HLV ; LVM_ENSUREVISIBLE
}

ExtListView_getFocusedControl(objLV) {
    ; https://www.autohotkey.com/boards/viewtopic.php?t=37120
    static vTIDAhk := DllCall("GetCurrentThreadId", "UInt")
    static GuiThreadInfo_Size:=24 + 6*A_PtrSize ;4 + 4 + 6*A_PtrSize + 16
    static offset_hwndFocus := 8 + 1*A_PtrSize
    ;   typedef struct tagGUITHREADINFO {
    ; DWORD cbSize; 0
    ; DWORD flags; 4
    ; HWND hwndActive;    8
    ; HWND hwndFocus;     8 + 1*A_PtrSize
    ; HWND hwndCapture;   8 + 2*A_PtrSize
    ; HWND hwndMenuOwner; 8 + 3*A_PtrSize
    ; HWND hwndMoveSize;  8 + 4*A_PtrSize
    ; HWND hwndCaret;     8 + 5*A_PtrSize
    ; RECT rcCaret;       8 + 6*A_PtrSize
    ;   }
    ; DWORD is Uint
    ; BOOL AttachThreadInput(
    ;   [in] DWORD idAttach,
    ;   [in] DWORD idAttachTo,
    ;   [in] BOOL  fAttach
    ; );
    ; BOOL -> Int
    vTID := DllCall("GetWindowThreadProcessId", "Ptr",objLV.hwnd, "Ptr",0, "UInt")


    VarSetCapacity(GuiThreadInfo, GuiThreadInfo_Size, 0)
	; GuiThreadInfo.cbSize = sizeof(GuiThreadInfo);
    NumPut(GuiThreadInfo_Size, GuiThreadInfo,0,"Uint")
    ; GetGuiThreadInfo(vTID, &GuiThreadInfo)
    DllCall("GetGUIThreadInfo", "Uint",vTID, "Ptr",&GuiThreadInfo)

    hwndFocus:=NumGet(GuiThreadInfo, offset_hwndFocus, "Ptr")

    return hwndFocus
}
___
I can't seem to make ExtListView_GetItemText work for an external listview
, I'm currently trying encoding "UTF-16", struct LVITEMW may be larger than LVITEMA, szreadbuf gets set from 11111 to " " so I guess no fatal error ?
, same TCHARs but not same VarSetCapacity

nvm, LVS_OWNERDATA:=0x1000
https://docs.microsoft.com/en-us/windows/win32/controls/lvm-getitemtext#remarks wrote:LVM_GETITEMTEXT is not supported under the LVS_OWNERDATA style.

Code: Select all

ControlGet, OutputStyle, Style ,,, % "ahk_id " objLV.hlv
MsgBox % OutputStyle & LVS_OWNERDATA:=0x1000
Last edited by MrDoge on 29 May 2022, 16:18, edited 1 time in total.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Help with focus\select specific line from SysListView321

Post by mikeyww » 29 May 2022, 15:29

I did not try this with an external ListView. You would need to use the correct window title. The instructions for selecting rows are provided with the function.

Post Reply

Return to “Ask for Help (v1)”