[LIB] ExtListView - get data from external ListViews

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
cyruz
Posts: 346
Joined: 30 Sep 2013, 13:31

[LIB] ExtListView - get data from external ListViews

08 May 2014, 05:35

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

*/
Last edited by cyruz on 24 Jul 2017, 03:20, edited 2 times in total.
ABCza on the old forum.
My GitHub.
kiwichick
Posts: 130
Joined: 21 Jan 2014, 22:03

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

10 May 2014, 19:52

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.
User avatar
cyruz
Posts: 346
Joined: 30 Sep 2013, 13:31

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

12 May 2014, 02:39

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...
ABCza on the old forum.
My GitHub.
Tigerite
Posts: 1
Joined: 02 Oct 2014, 04:44

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

02 Oct 2014, 04:57

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!
Dave_Scream
Posts: 7
Joined: 01 Jul 2016, 06:06

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

13 Apr 2017, 08:51

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.
User avatar
cyruz
Posts: 346
Joined: 30 Sep 2013, 13:31

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

24 Jul 2017, 03:22

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.
ABCza on the old forum.
My GitHub.
User avatar
joedf
Posts: 8940
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

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

11 Jun 2018, 15:08

This is really cool! :+1:
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

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

05 Dec 2020, 05:10

: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
}
MrDoge
Posts: 151
Joined: 27 Apr 2020, 21:29

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

23 Oct 2021, 12:27

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
}

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: charlie89 and 130 guests