Page 1 of 1

[LIB] ExtListView - get data from external ListViews

Posted: 08 May 2014, 05:35
by cyruz
Hi guys,

I wrote this library for a little project I'm developing, I hope it can be useful for someone. It can interact with ListViews owned by external processes. For now only some function are provided, please be free to update and share your code.

It should work on both x32 and x64, ANSI and Unicode, but I didn't test it extensively, so please report any bugs...

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, ^!g, TOGGLESEL
Return

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

QUIT:
ExtListView_DeInitialize(objLV)
ExitApp

*/

Re: [LIB] ExtListView - get data from external ListViews

Posted: 10 May 2014, 19:52
by kiwichick
Hi there, Sorry for the potentially silly question but I'm not sure what you mean by "external" ListViews? It would be a godsend if your script was the answer to my post here:

http://www.autohotkey.com/board/topic/1 ... stview321/

And if this is what I'm looking for, would you mind giving me a bit more of an idea how to use it and providing a little more example code? Cheers.

Re: [LIB] ExtListView - get data from external ListViews

Posted: 12 May 2014, 02:39
by cyruz
kiwichick wrote:Hi there, Sorry for the potentially silly question but I'm not sure what you mean by "external" ListViews? It would be a godsend if your script was the answer to my post here:

http://www.autohotkey.com/board/topic/1 ... stview321/

And if this is what I'm looking for, would you mind giving me a bit more of an idea how to use it and providing a little more example code? Cheers.
This library works only for normal ListViews (SysListView321) owned by processes other than the main script. The part related to the memory injection should work also in your case, but looks like that the application you want to read data from works in a different way...

Re: [LIB] ExtListView - get data from external ListViews

Posted: 12 May 2014, 04:01
by kiwichick
OK thanks, cyruz.

Re: [LIB] ExtListView - get data from external ListViews

Posted: 02 Oct 2014, 04:57
by Tigerite
Firstly thanks for this script, it's excellent and exactly what I needed. Unfortunately though I did find some bugs with this on Windows 8.1 x64 which were causing it not to work properly. Thanks to this script I was able to correct them and it now works perfectly.

Here are the fixes:

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_ToggleSelection
; Description ..: Select/deselect items in the target ListView.
; Parameters ...: objLV   - External ListView initializated 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,objLV.szwritebuf, UInt,0 ) )
        Throw Exception("objLV.pwritebuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)
    SendMessage, 0x102B, % nItem, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
}

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_GetItemText
; Description ..: Get the text of the desired item.
; Parameters ...: objLV - External ListView initializated 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)
}

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------
; 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 initializated 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 := 52 + (A_PtrSize * 2) + (A_PtrSize - 4) ; 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
}
Hope these help someone else out there!

Re: [LIB] ExtListView - get data from external ListViews

Posted: 13 Apr 2017, 08:51
by Dave_Scream
Thank you so much, this component was so helpful to me. Other solutions was too complicated and at some point stop to work. Your code work very well.

Re: [LIB] ExtListView - get data from external ListViews

Posted: 24 Jul 2017, 03:22
by cyruz
Tigerite wrote:Firstly thanks for this script, it's excellent and exactly what I needed. Unfortunately though I did find some bugs with this on Windows 8.1 x64 which were causing it not to work properly. Thanks to this script I was able to correct them and it now works perfectly.

Here are the fixes...
Almost 3 years passed, but thanks for this. I added the change to the code with a slight difference related to LVITEM size calculation.

Re: [LIB] ExtListView - get data from external ListViews

Posted: 11 Jun 2018, 15:08
by joedf
This is really cool! :+1:

Re: [LIB] ExtListView - get data from external ListViews

Posted: 05 Dec 2020, 05:10
by just me
:arrow: Need help in external listview set item:

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------
; Function .....: ExtListView_SetItemText
; Description ..: Set the text of the desired item.
; Parameters ...: objLV - External ListView initialized object.
; ..............: sText - The text to set.
; ..............: 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_SetItemText(ByRef objLV, ByRef sText, 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.

    VarSetCapacity( sBuf, objLV.szreadbuf, 0 )
    StrPut( sText, &sBuf, objLV.senc )

    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)

    If ( !DllCall( "WriteProcessMemory", Ptr,objLV.hproc, Ptr,objLV.preadbuf, Ptr,&sBuf, UInt,objLV.szreadbuf
                                       , UInt,0 ) )
        Throw Exception("objLV.preadbuf: error writing memory", "WriteProcessMemory", "LastError: " A_LastError)

    ; LVM_SETITEMTEXTA = 0x102E ; (LVM_FIRST + 46)
    ; LVM_SETITEMTEXTW = 0x1074 ; (LVM_FIRST + 116)

    LVM_SETITEMTEXT := (objLV.senc == "UTF-8" || objLV.senc == "UTF-16") ? 0x1074 : 0x102E
    SendMessage, %LVM_SETITEMTEXT%, %nRow%, % objLV.pwritebuf,, % "ahk_id " objLV.hlv
    Return ErrorLevel
}

Re: [LIB] ExtListView - get data from external ListViews

Posted: 23 Oct 2021, 12:27
by MrDoge
I needed and added

Code: Select all

; Focus and clicks last focused row || first row
ExtListView_RestoreFocus(objLV)

ExtListView_EnsureVisible(objLV, Row, fPartialOK:=false)
ExtListView_ClickRow(objLV, Row)
ExtListView_getFocusedControl(objLV)

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
}

Re: [LIB] ExtListView - get data from external ListViews

Posted: 23 May 2022, 08:12
by Tomer