Page 1 of 1

winapi: reading listview contents

Posted: Tue Jan 19, 2010 3:56 pm
by thefool
Hey!

I'm having a little trouble at work with a program that has no interface (of course it has a GUI, but you know what i mean). It stores some information in what looks like a standard listview (with 3 columns) and i need to get that information out for processing. I'll be spending more time on this myself of course, but i'm wondering if anyone here has done something like this before with success and can give me a hint?

Best regards :)

Re: winapi: reading listview contents

Posted: Tue Jan 19, 2010 11:39 pm
by IdeasVacuum
well, it displays the info in a list view, but maybe it is reading from a database? If so, then there is another maybe - collect the info from the db.

Re: winapi: reading listview contents

Posted: Wed Jan 20, 2010 1:12 am
by netmaestro
Of course it depends upon whether it's actually a SysListview32 (similar to PB ListIconGadget) or a ListBox (similar to PB ListviewGadget). Those are the classnames to look for. If it's a SysListview32, get its hwnd and send it the LVM_GETITEMCOUNT followed by a loop with LVM_GETITEMTEXT for each item. For a ListBox, send LB_GETCOUNT and LB_GETTEXT. Good hunting!

Re: winapi: reading listview contents

Posted: Wed Jan 20, 2010 1:56 pm
by thefool
IdeasVacuum wrote:well, it displays the info in a list view, but maybe it is reading from a database? If so, then there is another maybe - collect the info from the db.
Sadly not, its being collected realtime and i need to read it (almost) realtime. I could ask it to write to the disk very often (eventually a virtual ram disk or flash drive etc) but i think the other solution is better in this case.
netmaestro wrote:Of course it depends upon whether it's actually a SysListview32 (similar to PB ListIconGadget) or a ListBox (similar to PB ListviewGadget). Those are the classnames to look for. If it's a SysListview32, get its hwnd and send it the LVM_GETITEMCOUNT followed by a loop with LVM_GETITEMTEXT for each item. For a ListBox, send LB_GETCOUNT and LB_GETTEXT. Good hunting!
Great! Just what i need. Thanks :)

Re: winapi: reading listview contents

Posted: Wed May 30, 2012 9:23 am
by SeregaZ
so how to select some item in SysListview32?

Re: winapi: reading listview contents

Posted: Sat Jun 02, 2012 6:09 am
by SeregaZ
i made it! finaly! at last! i found how to right read items, and how to know what item is selected and select and focus another item :)

Code: Select all

Procedure GetItem(ID) 

Define LVItem.LVITEM
LVItem\StateMask = #LVIS_DROPHILITED
LVItem\State     = #LVIS_DROPHILITED

lvi.LVITEM 
_lvi.LVITEM 
temp.s 
Item.l 
Count=SendMessage_(ID,#LVM_GETITEMCOUNT,0,0)
GetWindowThreadProcessId_(ID, @pid)  
If pid 
 proc = OpenProcess_(#PROCESS_VM_OPERATION|#PROCESS_VM_READ|#PROCESS_VM_WRITE|#PROCESS_QUERY_INFORMATION, #False, pid) 
 If proc 
   *_lvi.LVITEM=VirtualAllocEx_(proc, 0, SizeOf(LVITEM), #MEM_COMMIT, #PAGE_READWRITE) 
   Item=VirtualAllocEx_(proc, 0, 255, #MEM_COMMIT, #PAGE_READWRITE) 
   temp=Space(255) 
   lvi\cchTextMax=255 
   null = 0 
         For i=0 To Count-1 
           *Buffer1=AllocateMemory(512) 
           If *Buffer1 
             lvi\iSubItem = 0 
             lvi\pszText = Item 
             lvi\cchTextMax = 255 
             WriteProcessMemory_(proc, *_lvi, @lvi, SizeOf(LVITEM), null) 
             LenString=SendMessage_(ID, #LVM_GETITEMTEXT, i, *_lvi)
             ReadProcessMemory_(proc, item, @temp, 255, null) 
             Debug temp
             If SendMessage_(ID,#LVM_GETITEMSTATE, i, #LVIS_SELECTED)
                Debug "selected was " + temp  
             EndIf
           EndIf 
         Next i
         
      VirtualFreeEx_(proc, *_lvi, 0, #MEM_RELEASE); 
      VirtualFreeEx_(proc, item, 0, #MEM_RELEASE) 
      CloseHandle_(proc)
  EndIf 
EndIf 
EndProcedure 



If OpenWindow(0, 10, 10, 200, 100, "for findwindow", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   ListIconGadget(0, 10, 10, 180, 80, "for findwindow ex", 170, #PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
   
   AddGadgetItem(0, -1, "first select")
   AddGadgetItem(0, -1, "second select")
   AddGadgetItem(0, -1, "third select")

   SetGadgetState(0, 0)
   
   SetActiveGadget(0)
   
   Repeat
      mainwind = FindWindow_(0, "for findwindow")
      Delay(100)
   Until mainwind
   
   Debug mainwind
   
   Repeat
      exwind = FindWindowEx_(mainwind, 0, "SysListView32", 0)
      Delay(100)
   Until exwind
   
   GetItem(exwind) 

;{ select and focus third item
   State.LVITEM 
   State\mask = #LVIF_STATE
   State\state = #LVIS_SELECTED | #LVIS_FOCUSED
   State\stateMask = #LVIS_SELECTED | #LVIS_FOCUSED
   SendMessage_(exwind, #LVM_SETITEMSTATE, 2, @State)
  ;exwind handle of SysListView32 class window.
  ;2 it is number of item in list. numbers begin from 0. 0 = 1 item, 1 = 2 item, 2 = 3 item, and etc.
;}

   Repeat
       Event = WaitWindowEvent()
   Until Event = #PB_Event_CloseWindow 
EndIf

Re: winapi: reading listview contents

Posted: Fri Sep 21, 2012 7:41 am
by SeregaZ
why this code work so unstable? i try to apply this code to read some iexplore window with select certificate, but or didnt work, or double select:
Image

how to fix it? where is thin spot in this code? what the secret?
(XP, explorer 6 or 7 or 8, threadsafe and unicode checks in compiler)

i think problem is in delay. and some time code start to work fine with debug. if remove debug command - the same code - not working.

and after select need to press enter:

Code: Select all

PostMessage_(exwind,#WM_KEYDOWN,13,0)
PostMessage_(exwind,#WM_KEYUP,13,0)
but it is too fast - window no time to select enter aready pressed.
if i put delay betweeen select and enter - programm create double select. the same with sleep_(). how to make some kind of pause between select and pressing enter?

Re: winapi: reading listview contents

Posted: Fri Sep 21, 2012 6:53 pm
by SeregaZ
i see SendMessage_(exwind, #LVM_SETITEMSTATE, 2, @State) not enough. it need to open memory iexplore and many operation. who can convert to PureBasic this code?

Code: Select all

int SelectList(HWND hList, int iIndex)

{

    /* get process Id, that has ListView */

    GetWindowThreadProcessId(hList, pid);

 

    if(!pid){

 

        /* open process with rights */

        HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE|PROCESS_VM_OPERATION, TRUE, pid);

 

        if(!hProcess){



            /* allocate memory in target process */

            LPVOID lpMem = VirtualAllocEx(hProcess, NULL, sizeof(LV_ITEM), MEM_COMMIT, PAGE_READWRITE);

 

            if(!lpMem){

 

                /* fill structure  */

                LV_ITEM LV;

                LV.state = LVIS_SELECTED;

                LV.mask = LVIS_SELECTED;

 

                SIZE_T cdWrite;

 

                /* copy LV to target process */

                if (WriteProcessMemory(hProcess, lpMem, &LV, sizeof(LV_ITEM), &cdWrite))

                {

                    /* send message to select */

                    SendMessage(hList, LVM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)lpMem);

                }

 

                /* free allocate memory */

                VirtualFreeEx(hProcess, lpMem, 0, MEM_RELEASE);

            }

            /* close handle*/

            CloseHandle(hProcess);

        }

    }

}
i try to do this, but nothing... didnt work.

Code: Select all

Procedure SelectList(hList.i, iIndex.i)
  
  ;/* get process Id, that has ListView */
  GetWindowThreadProcessId_(hList, @pid)
  
  If pid
    
    ;/* open process With rights */  
    hProcess = OpenProcess_(#PROCESS_VM_WRITE|#PROCESS_VM_OPERATION, #True, pid);
    If hProcess
    
      ;/* allocate memory in target process */
      lpMem = VirtualAllocEx_(hProcess, #Null, SizeOf(LVITEM), #MEM_COMMIT, #PAGE_READWRITE)
      If lpMem
        
        ;/* fill Structure  */
        LV.LVITEM
        LV\state = #LVIS_SELECTED;
        LV\mask = #LVIS_SELECTED;
        
        ;/* copy LV To target process */
        If WriteProcessMemory_(hProcess, lpMem, @LV, SizeOf(LVITEM), @cdWrite)

          ;/* send message To Select */
          SendMessage_(hList, #LVM_SETITEMSTATE, iIndex, @lpMem);
          
        EndIf
        
        ;/* free allocate memory */
        VirtualFreeEx_(hProcess, lpMem, 0, #MEM_RELEASE);
        
      EndIf
      
      ;/* close handle*/
      CloseHandle_(hProcess);
      
    EndIf 
    
  EndIf
   
EndProcedure


SelectList(8192804, 3)

Re: winapi: reading listview contents

Posted: Fri Sep 21, 2012 7:17 pm
by netmaestro
Give this one a try:

Code: Select all

Procedure SelectList(hList, iIndex)
  
  ;/* get process Id, that has ListView */
  GetWindowThreadProcessId_(hList, pid)
  
  If pid
    
    ;/* open process With rights */
    hProcess = OpenProcess_(#PROCESS_VM_WRITE|#PROCESS_VM_OPERATION, #True, pid)
    
    If hProcess
      
      ;/* allocate memory in target process */
      lpMem = VirtualAllocEx_(hProcess, #Null, SizeOf(LV_ITEM), #MEM_COMMIT, #PAGE_READWRITE)
       
      If lpMem
         
        ;/* fill Structure  */
        With LV.LV_ITEM;
          \state = #LVIS_SELECTED
          \mask = #LVIS_SELECTED
        EndWith
        
        ;/* copy LV To target process */
        If (WriteProcessMemory_(hProcess, lpMem, @LV, SizeOf(LV_ITEM), @cdWrite.l))
          
          ;/* send message To Select */
          SendMessage_(hList, #LVM_SETITEMSTATE, iIndex, lpMem)
          
        EndIf

        ;/* free allocate memory */
        VirtualFreeEx_(hProcess, lpMem, 0, #MEM_RELEASE)
        
      EndIf
      
      ;/* close handle*/
      CloseHandle_(hProcess)
      
    EndIf
    
  EndIf
  
EndProcedure

Re: winapi: reading listview contents

Posted: Fri Sep 21, 2012 7:32 pm
by SeregaZ
no, didnt work.

try to change GetWindowThreadProcessId_(hList, pid) to a GetWindowThreadProcessId_(hList, @pid) :)

and

Code: Select all

        With LV.LV_ITEM;
          \state = #LVIS_SELECTED
          \mask = #LVIS_SELECTED
        EndWith
to

Code: Select all

        With LV.LV_ITEM;
          \state = #LVIS_SELECTED|#LVIS_FOCUSED
          \mask = #LVIF_STATE
          \stateMask = #LVIS_SELECTED|#LVIS_FOCUSED
        EndWith
now looks goood :)

Re: winapi: reading listview contents

Posted: Sun Jan 22, 2017 6:32 pm
by SeregaZ
for example another, not my programm, have some kind of this:

Code: Select all

Enumeration
  #Window
  
  #Container
  #ListIcon
EndEnumeration

If OpenWindow(#Window, 100, 100, 300, 105, "Window for cathc", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   ContainerGadget(#Container, 5, 5, 290, 95, #PB_Container_Raised)

   ListIconGadget(#ListIcon, 5, 5, 270, 75, "Name", 100, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection | #LVS_NOCOLUMNHEADER | #PB_ListIcon_CheckBoxes)
   AddGadgetItem(#ListIcon, -1, "Harry Rannit")
   AddGadgetItem(#ListIcon, -1, "Ginger Brokeit")
   AddGadgetItem(#ListIcon, -1, "3 par")
   AddGadgetItem(#ListIcon, -1, "num four")
   
   CloseGadgetList()
   Repeat
     Event = WaitWindowEvent()
   Until Event = #PB_Event_CloseWindow
 EndIf
save it with some "testwindow.exe" file, launch. then start code below.

i know how to read it. and maybe select one - by press "space" after select. i mean checkbox. but how to return checkbox is check or not check?

Code: Select all

Procedure.i SelectItem(pid.i, hwnd.i, toselectitem.i)
  ;/* get process Id, that has ListView */
  ;GetWindowThreadProcessId_(hList, @pid)
  If pid
    ;/* open process With rights */
    hProcess = OpenProcess_(#PROCESS_VM_WRITE|#PROCESS_VM_OPERATION, #True, pid)
    If hProcess
      ;/* allocate memory in target process */
      lpMem = VirtualAllocEx_(hProcess, #Null, SizeOf(LV_ITEM), #MEM_COMMIT, #PAGE_READWRITE)
      If lpMem
        ;/* fill Structure  */
        With LV.LV_ITEM;
          \state = #LVIS_SELECTED|#LVIS_FOCUSED
          \mask = #LVIF_STATE
          \stateMask = #LVIS_SELECTED|#LVIS_FOCUSED
        EndWith
        ;/* copy LV To target process */
        If (WriteProcessMemory_(hProcess, lpMem, @LV, SizeOf(LV_ITEM), @cdWrite.l))
          ;/* send message To Select */
          ret = SendMessage_(hwnd, #LVM_SETITEMSTATE, toselectitem, lpMem)          
        EndIf
        ;/* free allocate memory */
        VirtualFreeEx_(hProcess, lpMem, 0, #MEM_RELEASE)        
      EndIf      
      ;/* close handle*/
      CloseHandle_(hProcess)      
    EndIf    
  EndIf
  
  ProcedureReturn ret
  
EndProcedure

Procedure.i NumberItem(pid.i, hwnd.i, selectitem$)

  toselectitem = -2
  
  lvi.LVITEM 
  _lvi.LVITEM 
  
  temp.s 
  Item.l 
  
  Count = SendMessage_(hwnd,#LVM_GETITEMCOUNT,0,0)
  
  proc = OpenProcess_(#PROCESS_ALL_ACCESS, #False, pid)

  If proc

    *_lvi.LVITEM = VirtualAllocEx_(proc, 0, SizeOf(LVITEM), #MEM_COMMIT, #PAGE_READWRITE) 
    Item         = VirtualAllocEx_(proc, 0,            255, #MEM_COMMIT, #PAGE_READWRITE)

    temp = Space(255) 

    lvi\cchTextMax=255 

    For i=0 To Count-1 
      
      lvi\iSubItem = 0 
      lvi\pszText = Item 
      lvi\cchTextMax = 255 
      WriteProcessMemory_(proc, *_lvi, @lvi, SizeOf(LVITEM), 0) 
      
      ; i need same as #LVM_GETITEMTEXT, but for checkbox?
      SendMessage_(hwnd, #LVM_GETITEMTEXT, i, *_lvi) 
      ReadProcessMemory_(proc, item, @temp, 255, 0)
      Debug temp
        
      If temp = selectitem$
        toselectitem = i
        Break               
      EndIf
      
    Next i
    VirtualFreeEx_(proc, *_lvi, 0, #MEM_RELEASE); 
    VirtualFreeEx_(proc, item, 0, #MEM_RELEASE)
    CloseHandle_(proc)
  EndIf

  ProcedureReturn toselectitem
    
EndProcedure

Prototype ProcessFirst(Snapshot, Process)
Prototype ProcessNext(Snapshot, Process)
Global ProcessFirst.ProcessFirst
Global ProcessNext.ProcessNext

Procedure GetPidProcess2(Name.s) ; Returns 'pid' of the first Process found if it exists / 0 if it doesn't exist
  
  
  Protected ProcLib
  Protected ProcName.s
  Protected Process.PROCESSENTRY32
  Protected x
  Protected retval=#False
  Name=UCase(Name.s)
  ProcLib= OpenLibrary(#PB_Any, "Kernel32.dll") 
  If ProcLib
    CompilerIf #PB_Compiler_Unicode
      ProcessFirst           = GetFunction(ProcLib, "Process32FirstW") 
      ProcessNext            = GetFunction(ProcLib, "Process32NextW") 
    CompilerElse
      ProcessFirst           = GetFunction(ProcLib, "Process32First") 
      ProcessNext            = GetFunction(ProcLib, "Process32Next") 
    CompilerEndIf
    If  ProcessFirst And ProcessNext 
      Process\dwSize = SizeOf(PROCESSENTRY32) 
      Snapshot =CreateToolhelp32Snapshot_(#TH32CS_SNAPALL,0)
      If Snapshot 
        ProcessFound = ProcessFirst(Snapshot, Process) 
        x=1
        While ProcessFound 
          ProcName=PeekS(@Process\szExeFile)
          ProcName=GetFilePart(ProcName)
          If UCase(ProcName)=UCase(Name) 
            ret=Process\th32ProcessID
            Break
          EndIf
          
          ProcessFound = ProcessNext(Snapshot, Process) 
          x=x+1  
        Wend 
      EndIf 
      CloseHandle_(Snapshot) 
    EndIf 
    CloseLibrary(ProcLib) 
  EndIf 
  ProcedureReturn ret
  
EndProcedure

 


pid = GetPidProcess2("testwindow.exe") ; from droopy

hwndmain = FindWindow_(0, "Window for cathc")
If hwndmain

  SetForegroundWindow_(hwndmain)
  
  hwndpanel = FindWindowEx_(hwndmain, 0, "PureContainer", 0)

  If hwndpanel

    hwnd = FindWindowEx_(hwndpanel, 0, "SysListView32", 0)
    
    selectnum = NumberItem(pid, hwnd, "Ginger Brokeit")

    If selectnum > -2
      If SelectItem(pid, hwnd, selectnum)
        Debug "select done"
        
        ; space button       
        Delay(100)
        PostMessage_(hwnd, #WM_KEYDOWN, 32, 0) 
        Delay(100)
        PostMessage_(hwnd, #WM_KEYUP, 32, 0)
        
      EndIf
    EndIf
    
  EndIf
EndIf


Re: winapi: reading listview contents

Posted: Mon Jan 23, 2017 12:07 pm
by SeregaZ
i found some ListView_GetCheckState macro https://msdn.microsoft.com/en-us/librar ... s.85).aspx
but probably it have no windows XP support.
Minimum supported client Windows Vista [desktop apps only]

how i can get state check or not check of this checkboxes of another application?