Results 1 to 18 of 18

Thread: Get text from ListView in another app

  1. #1

    Thread Starter
    New Member
    Join Date
    Jul 2002
    Location
    Essex, England
    Posts
    4

    Get text from ListView in another app

    I think that it works different with a ListView than it does a ListBox for some reason. When Program A tries to get the text from a ListView in Program B, Program B crashes. Someone explained to me that Program A is trying to write to the memory of Program be or vice versa (something like that anyway), which apparently is a big no no.

    The code I'm using is as follows:

    Code:
    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _
        ByVal hWnd1 As Long, _
        ByVal hWnd2 As Long, _
        ByVal lpsz1 As String, _
        ByVal lpsz2 As String) As Long
    
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
        ByVal hwnd As Long, _
        ByVal wMsg As Long, _
        ByVal wParam As Long, _
        lParam As Any) As Long
        
    Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" ( _
        ByVal hwnd As Long, _
        ByVal wMsg As Long, _
        ByVal wParam As Long, _
        lParam As Any) As Long
        
    Private Type LVITEM
        mask        As Long
        iItem       As Long
        iSubItem    As Long
        state       As Long
        stateMask   As Long
        pszText     As String
        cchTextMax  As Long
        iImage      As Long
        lParam      As Long
    End Type
    
    
    Private Const BM_CLICK = &HF5&
    Private Const WM_SETTEXT = &HC
    
    Private Const LVM_FIRST = &H1000
    Private Const LVM_GETITEMCOUNT = (LVM_FIRST + 4)
    
    Private Const LVM_GETITEM = (LVM_FIRST + 5)
    Private Const LVM_GETSTRINGWIDTH = (LVM_FIRST + 17)
    Private Const LVM_GETCOLUMN = (LVM_FIRST + 25)
    Private Const LVM_GETITEMTEXT = (LVM_FIRST + 45)
    
    Dim Lv As LVITEM
    Dim MyText As String
    Dim MySize As Long
    
    
    Private Sub Command1_Click()
    
    test123 = FindWindowEx(0, 0, vbNullString, "Test123")
    frame1 = FindWindowEx(test123, 0, "ThunderFrame", vbNullString)
    frame2 = FindWindowEx(frame1, 0, "ThunderFrame", vbNullString)
    button = FindWindowEx(frame2, 0, "ThunderCommandButton", vbNullString)
    LView = FindWindowEx(frame2, 0, "ListView20WndClass", vbNullString)
    
    NumBuddies = SendMessage(LView, LVM_GETITEMCOUNT, 0, 0)
    
    'Lv.mask = LVIF_TEXT
    'Lv.iItem = 1
    Lv.cchTextMax = Len(MyText)
    Lv.pszText = MyText
    
    MySize = SendMessage(LView, LVM_GETITEMTEXT, ByVal 1, ByVal Lv)
    
    
    Text1.Text = test123
    Text2.Text = frame1
    Text3.Text = frame2
    Text4.Text = button
    Text5.Text = LView
    Text6.Text = NumBuddies
    Text7.Text = MySize
    Text8.Text = MyText
    End Sub

    I don't quite understand the LVITEM thing, so maybe that's where I'm going wrong.

    I've again uploaded the example programs to show what I am trying to achieve. You'll see that when Program A tries to get the text from a ListView in Program B, Program B crashes

    I've read here that it is not possible to do it this way, but instead you have to use some other way whuch I is competly beyond me. Surely it should be possible and not too much omplicated as getting text from a ListBox¿

    It may not be as complicated as it seems and might be me just missing something simple, but I'm new to all this so I'm not sure where I'm going wrong

    Any help would be much appreciated.
    Thanks

  2. #2
    the reason your program does not work is because the LVItem structure is not created within the same memort space as the program into which you are sending it in. when dealing with Listviews, Treeviews, etc you must create the structure within the other processes virtual memory space and then send it in.

    use this function i wrote up to accomplish the task.

    Code:
    Public Const PROCESS_QUERY_INFORMATION = 1024
    Public Const PROCESS_VM_OPERATION = &H8
    Public Const PROCESS_VM_READ = &H10
    Public Const PROCESS_VM_WRITE = &H20
    Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
    Public Const MAX_LVMSTRING As Long = 255
    Public Const MEM_COMMIT = &H1000
    Public Const PAGE_READWRITE = &H4
    Public Const LVIF_TEXT As Long = &H1
    
    Public Type LV_ITEMA
       mask         As Long
       iItem        As Long
       iSubItem     As Long
       state        As Long
       stateMask    As Long
       pszText      As Long
       cchTextMax   As Long
       iImage       As Long
       lParam       As Long
       iIndent      As Long
    End Type
    
    Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
    Public Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
    Public Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
    Public Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
    Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
    
    Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
    
    Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    
    Public Function GetListviewItem(ByVal hWindow As Long, ByVal ProcessID As Long, ByVal pColumn As Long, ByVal pRow As Long) As String
        Dim result              As Long
        Dim myItem              As LV_ITEMA
        Dim pHandle             As Long
        Dim pStrBufferMemory    As Long
        Dim pMyItemMemory       As Long
        Dim strBuffer()         As Byte
        Dim index               As Long
        Dim tmpString           As String
        Dim strLength           As Long
        
        '**********************
        'init the string buffer
        '**********************
        ReDim strBuffer(MAX_LVMSTRING)
        
        '***********************************************************
        'open a handle to the process and allocate the string buffer
        '***********************************************************
        pHandle = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, ProcessID)
        pStrBufferMemory = VirtualAllocEx(pHandle, 0, MAX_LVMSTRING, MEM_COMMIT, PAGE_READWRITE)
            
        '************************************************************************************
        'initialize the local LV_ITEM structure
        'The myItem.iSubItem member is set to the index of the column that is being retrieved
        '************************************************************************************
        myItem.mask = LVIF_TEXT
        myItem.iSubItem = pColumn
        myItem.pszText = pStrBufferMemory
        myItem.cchTextMax = MAX_LVMSTRING
        
        '**********************************************************
        'write the structure into the remote process's memory space
        '**********************************************************
        pMyItemMemory = VirtualAllocEx(pHandle, 0, Len(myItem), MEM_COMMIT, PAGE_READWRITE)
        result = WriteProcessMemory(pHandle, pMyItemMemory, myItem, Len(myItem), 0)
        
        '*************************************************************
        'send the get the item message and write back the memory space
        '*************************************************************
        result = SendMessage(hWindow, LVM_GETITEMTEXT, pRow, ByVal pMyItemMemory)
        result = ReadProcessMemory(pHandle, pStrBufferMemory, strBuffer(0), MAX_LVMSTRING, 0)
        result = ReadProcessMemory(pHandle, pMyItemMemory, myItem, Len(myItem), 0)
          
        '**************************************************
        'turn the byte array into a string and send it back
        '**************************************************
        For index = LBound(strBuffer) To UBound(strBuffer)
            If Chr(strBuffer(index)) = vbNullChar Then Exit For
            tmpString = tmpString & Chr(strBuffer(index))
        Next index
        
        tmpString = Trim(tmpString)
        
        '**************************************************
        'deallocate the memory and close the process handle
        '**************************************************
        result = VirtualFreeEx(pHandle, pStrBufferMemory, 0, MEM_RELEASE)
        result = VirtualFreeEx(pHandle, pMyItemMemory, 0, MEM_RELEASE)
        
        result = CloseHandle(pHandle)
        
        If Len(tmpString) > 0 Then GetListviewItem = tmpString
    
    End Function

  3. #3
    Addicted Member MathImagics's Avatar
    Join Date
    Jun 2002
    Location
    Uki, NSW Australia
    Posts
    169
    Might I just add that comparing a ListBox with a ListView is a bit like comparing a car with an aircraft!

    Still, I understand and sympathise with Britomo's incredulity, which I remember having myself when I first crashed my PC trying the very same !!

    Anyway, it's a good thing, especially if it makes you want to understand exactly why your initial attempt crashed out! Call this lesson "Foreign Process Data Extraction 101".

    Once you've understood this, you should then be ready for the "FPDE 101" exam question:

    ==============================================
    Q1. "How come it works for ListBox'es??? Shouldn't it fail for the very same reasons it fails for ListView's ????"
    Discuss (max 1500 words)
    ==============================================

    Q2. "Why is Windows programming so much fun????"
    Give reasons!
    ==============================================


    Dr Memory
    Last edited by MathImagics; Jul 7th, 2002 at 01:55 AM.
    "He's got a B.A. (in be-bop), a Ph.D. (in swing), he's a Master of Rhythm, he's the Rock'n'Roll king" ("The Rock'n'Roll Doctor", Lowell George)

    "If you push something hard enough, it will fall over" (Fudd's Third Law of Opposition)

  4. #4
    MathImagics:

    hehe.. it was a fun (and challenging) problem when i was first faced with it, but the code was not all that difficult. main thing that i didnt understand (at the time), is why i was able to get the Listbox item text via SendMessage, but not the list view... I wasn't thinking about the whole foriegn process thing at the time.

    Brimito -- if you want a hint as to what the anser to MathImagic's first question is, think about the origin of the ListView. The time it came into being (as a control) has something to do with the answer

    btw: way back when I was working on this, I found a very dated Microsoft Developer's Journal article that was *very* informative. does this publication still exist? It seemed like a *very* good resource for windows coding/api info.

  5. #5

    Thread Starter
    New Member
    Join Date
    Jul 2002
    Location
    Essex, England
    Posts
    4
    Thanks for replying

    Looking at that function you wrote hax0r, I'm completly lost . I could have a go at implementing it in my app, but I have no idea where to start or how it all works . I had no idea that this little app would get so complicated hehe. My knowledge of VB is pretty limited at the moment and I'm only just learning about API, which I understand alot better than I used to
    All this about writing to the other programs memory space is unfortunately waay beyond me . I see that the function is well commented, but I still do not understand how it would all fit in exactly. It would be good if you could explain a little more about. However, I don't expect you to, as I don't even know where to start with it. Spot the newbie

    If I fail to get to grips with that function, then I think I might be able to get the items in the ListView 1 at a time. It would be a cumbersome way to go about it, but basically when a user double clicks on an item in the listview, another window open with the item text in a combobox. So I was thinking about sending BM_CLICK to the listview, then find the handle of the combo box and get the text from there, then closing that window and going back to the listview and doing the whole thing over again for the next item etc. Very long winded, but that's the only other way I can think of doing it.

    I've tried sending BM_CLICK to the listview, but I couldn't get it to work. I can get it to work for commandbutton though.
    Call PostMessage(button, BM_CLICK, 0, ByVal 0&)

    Would I have to use SendInput for a listview instead or something¿

    Also, the long winded workaround that I'm thinking of doing, how doable is it¿ I mean, would it take long to repeat that process for about 100 - 200 items in the listview and would the user still be able to use mouse and keyboard in another app¿

    Thanks again for your time and advice, much appreciated

  6. #6
    You won't be able to get the items one at a time in the external listview. you have to understand process / memory bounds. sure, the GET_ITEM call of a listbox works with an external app, but the same is not the case when it comes to a listview, treeview, or any other control which did not exist under Windows 3.1. if you want the answer as to why this is the case, then do some research -- it will help you out in the long run

    in anycase, i think using the function is relatively self explanatory. you send in a handle to a listview, the process ID of the foreign executable, and the row/column you want the item text for. looking at your code, you have almost all of that information already -- have for maybe the process ID. do a bit of research and you'll find how you can obtain the process ID from an hWnd -- if you're still stuck, reply back and I'll help.

    You wanted an explanation of how the function works -- well, here it goes :

    basically, the function allocates an LV_ITEM structure (in 'C' speak), ie: notice that the pszText item is a long, and not a VB string variable. This is the case because relatively speaking, strings in C are arrays of characters, and by default - windows is expecting a pointer to an array or chars (thus the long). Also, since you need to send in the length of the LV_ITEM structure into the WriteProcessMemory call, you can't use an open ended / nondefined length such as an un-initialized Vb String.

    Since the ListView you are querying is in an external process, the recieving program will not properly be able to process your SendMessage command since the memory location of the structure you are sending in (for it to fill out) resides outside of its own memory scope. Thus, you need to "create" the structure in its own memory scope so that it can properly "fill it in". After it is "filled in", you need to have windows re-create that strure within the memory scope of your application -- so you can read it.

    Basically, the gist of it is that any given process *cannot* access/modify memory locations outside of its scope. The Listbox, Textbox and certain other controls which can be utilized with SendMessage and which existed under Windows 3.1 are exceptions to this rule. Do your homework and report back to me tomorrow with you answer as to why this is the case.

    As it stands, you should be able to "copy/paste" my code into your program and make it do what you want it to -- not that I am advocating this approach towards VB coding, but it attempting to implement my code might serve as a learning experience for you.

    I think that too often people who read these forums take things for granted, and consider themselves "experts" without knowing a damn **** about what they are copying/pasting.

    - hax

  7. #7
    Fanatic Member alexandros's Avatar
    Join Date
    Oct 2002
    Location
    Milky Way Galaxy
    Posts
    694

    Re: Get text from ListView in another app

    I tried this function but it did not have any result. It only returned null strings .
    Do you possibly know what went wrong ?
    I got the window handle and the process id of an external program but it did
    not return the contents of the listview item.

  8. #8

    Re: Get text from ListView in another app

    If it is an owner drawn ListView you will not be able to retrive its contents.

  9. #9
    Fanatic Member alexandros's Avatar
    Join Date
    Oct 2002
    Location
    Milky Way Galaxy
    Posts
    694

    Re: Get text from ListView in another app

    Quote Originally Posted by hax0r
    If it is an owner drawn ListView you will not be able to retrive its contents.
    yes it is an owner drawn listview. why can't i read its contents ?
    is there another way to do this ?

  10. #10
    Super Moderator manavo11's Avatar
    Join Date
    Nov 2002
    Location
    Around the corner from si_the_geek
    Posts
    7,171

    Re: Get text from ListView in another app

    Quote Originally Posted by alexandros
    yes it is an owner drawn listview. why can't i read its contents ?
    is there another way to do this ?
    If it's owner drawn it's subclassed. It won't process the message you send I think.


    Has someone helped you? Then you can Rate their helpful post.

  11. #11
    Frenzied Member ice_531's Avatar
    Join Date
    Aug 2002
    Location
    Sitting w/ Bob Status: -Next -To- Null- Friend: Philip
    Posts
    1,152

    Re: Get text from ListView in another app

    Quote Originally Posted by manavo11
    If it's owner drawn it's subclassed. It won't process the message you send I think.

    Negative. If something is subclassed, you can still get contents by subclassing it yourself.
    :::`DISCLAIMER`:::
    Do NOT take anything i have posted to be truthful in any way, shape or form.
    Thank You!

    --------------------------------
    "Never heard about "hiking" poles. I usualy just grab a stick from the nature, and use that as a pole." - NoteMe
    "Finaly I can look as gay as I want..." - NoteMe
    Languages: VB6, BASIC, Java, C#. C++

  12. #12

    Re: Get text from ListView in another app

    This is not necesarily true. Since the ListView is owner drawn, it is reposinble for painting its own contents. This totally *can* bypasses the 'ItemText' collection of the ListView. If the ListView is rendering a graphical representation of the text on screen and not exposing any events which can be used to retrieve the internal data, you are stuck. Once 'My List Item' is rendered graphically on screen, there is no real easy way to convert that graphical representation back to its constiuent text.

    While its true you can subclass something via an external hook and trap its messages that doesn't really get you much when all you end up getting is WM_PAINTs.

  13. #13
    New Member
    Join Date
    Mar 2006
    Posts
    2

    Re: Get text from ListView in another app

    I worked on something like this a ways back, and OpenProcess() failed everytime.
    I tried the above function, and it fails at the OpenProcess() aswell
    all the parameters are right, any ideas why it would be failing everytime?

  14. #14

    Re: Get text from ListView in another app

    You probably do not have access to open the process. Are you a local administrator?

  15. #15
    New Member
    Join Date
    Mar 2006
    Posts
    2

    Re: Get text from ListView in another app

    I am yes.
    And the Process show's as my User in task manager.

  16. #16
    New Member
    Join Date
    Mar 2006
    Posts
    3

    Re: Get text from ListView in another app

    Peace All
    Haxor's script workrd for me but I had to go everytime to the the task manager and find the process Id of the main Process. or by using spy++. Some one else in the same Forum offerd this script to

    Dim processID As Long
    Dim proc As Long

    '/// get the processID of the listview ...
    GetWindowThreadProcessId(" handle to Listview here !!! " , processID)
    '/// now you have the processID ...
    proc = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE Or PROCESS_QUERY_INFORMATION , False, processID)

    But This Script doesnt return the right Process ID fro some unkown reasons, can anyone give a hint

  17. #17
    New Member ir_pro's Avatar
    Join Date
    Oct 2007
    Location
    Iran - Asia - - Gilan
    Posts
    6

    Re: Get text from ListView in another app

    how can i grab listview in yahoo room !
    in to my own list in vb form!?

  18. #18
    Addicted Member
    Join Date
    Jan 2008
    Location
    Essex, UK
    Posts
    149

    Re: Get text from ListView in another app

    Anyone got a working example of this code in .NET 2005 as i cant seem to get mine to convert correctly?
    Development Enviroment: Visual Studio 2008, VB.NET

    Recommend Winspector, far better then SPY++
    http://www.windows-spy.com/

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width