CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Apr 2007
    Posts
    162

    PostMessage to a list control

    I am trying to select an entry on a list control in another app. to make it look like I just left clicked on that particular list entry.

    I am trying this code but it doesn't work, no errors but the result is not what I want.

    Code:
    HWND TargetWindow = ::FindWindow(_T("#32770"),_T("MYAPP"));
    	if(TargetWindow != NULL){
    		//AfxMessageBox(_T("Found the Window"),MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_TOPMOST);
    		CWnd *ListHandle = FindWindowEx(TargetWindow,NULL,_T("SysListView32"),NULL);
    		if(ListHandle != NULL){
    			//AfxMessageBox(_T("Found the List Handle"),MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_TOPMOST);
    			LVITEM lvitem;
    			lvitem.mask=LVIF_PARAM|LVIF_STATE;
    			lvitem.iItem=10;
    			lvitem.iSubItem=0;
    			lvitem.state=LVIS_SELECTED|LVIS_FOCUSED;
    			BOOL Success = ListHandle->PostMessage(LVM_SETITEM,0,(LPARAM)&lvitem);
    			if(Success == 0)
    				AfxMessageBox(_T("PostMessage failed"),MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_TOPMOST);
    
    		}
    	}else{
    		AfxMessageBox(_T("Could not find the Window"),MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_TOPMOST);
    	}

  2. #2
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: PostMessage to a list control

    You have two problems:
    1. Your lvitem is local variable, which will go out of scope right after PostMessage, which might be processed after that memory is reused.
    2. The memory for your lvitem is in the address space of the calling app, and it makes no sence in the context of list control in another app.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  3. #3
    Join Date
    Apr 2007
    Posts
    162

    Re: PostMessage to a list control

    So, barring the local variable, you are saying I have to write the LVITEM to the target process memory, then use SendMessage then read the results from the target process? Is this the only way it can be done ?

  4. #4
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: PostMessage to a list control

    Your other alternative is to use messages that do not use pointers, only values in WPARAM, LPARAM and return in LRESULT.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  5. #5
    Join Date
    Apr 2007
    Posts
    162

    Re: PostMessage to a list control

    Sounds like I am SOL!
    Do you have any idea how to set the item state using what you suggest ?

  6. #6
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: PostMessage to a list control

    I would do what you suggested in your previous post.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  7. #7
    Join Date
    Apr 2007
    Posts
    162

    Re: PostMessage to a list control

    Ok so here is a shot at writing the LVITEM to the target process memory with a lot of help from a blog by Chris Taylor.
    Code:
    CString Title;
    const DWORD dwBufSize = 1024;
    DWORD dwTargetProcessID;
    BYTE *lpRemoteBuffer;
    HANDLE hProcess;
    LVITEM lvItem;
    int iIndex=14;
    
    
    BYTE lpLocalBuffer[dwBufSize] = {0};
    HWND TargetWindow = ::FindWindow(_T("#32770"),_T("MYAPP"));
    ::SetActiveWindow(TargetWindow);
    HWND ListHandle = ::FindWindowEx(TargetWindow,NULL,_T("SysListView32"),NULL);
    GetWindowThreadProcessId(TargetWindow, &dwTargetProcessID);
    hProcess = ::OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwTargetProcessID );
    
    lpRemoteBuffer = (BYTE*)::VirtualAllocEx( hProcess, NULL, dwBufSize,MEM_COMMIT, PAGE_READWRITE );
    lvItem.mask=LVIF_STATE;
    lvItem.state=LVIS_SELECTED | LVIS_FOCUSED;// tried it with and without this
    lvItem.stateMask=LVIS_SELECTED | LVIS_FOCUSED;
    lvItem.iItem=iIndex;
    lvItem.iSubItem=0;
    
    int Ret = 0;
    
    Ret = ::WriteProcessMemory( hProcess, (LPVOID)lpRemoteBuffer, &lvItem, sizeof(LVITEM), NULL );
    	
    Ret = ::SendMessage( ListHandle, LVM_SETSELECTIONMARK,0,iIndex);
    Ret = ::SendMessage( ListHandle, LVM_SETITEMSTATE,0,(LPARAM)lpRemoteBuffer);
    Ret = ::SendMessage( ListHandle, LVM_UPDATE, iIndex, 0);
    
    // Clean-up
    ::VirtualFreeEx( hProcess, (LPVOID)lpRemoteBuffer, 0, MEM_RELEASE ); 
    ::CloseHandle( hProcess );
    No errors, debug shows WriteProcessMemory and all three sendmessage commands getting through with the proper returns. Problem is, it always sets the item state for the first (zero) entry. It doesn't appear to be reading the lvItem.iItem setting.
    Suggestions ?

  8. #8
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: PostMessage to a list control

    You need to allocate memory in the other process for LVITEM too.

    In other words, you need two calls to VirtualAllocEx: a first for the text buffer (which you are doing), and a second for the LVITEM (which you are not doing).

    As one example, look at the source code for the freeware application called "Control Content Saver", which can be found at http://jacquelin.potier.free.fr/controlcontentsaver/. In particular for your purposes (which involve a list-view control), look at the function called CRemoteCtrlContentSaver::SaveListViewContent(), which can be found in the RemoteCtrlContentSaver.cpp file.

    Mike

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

Featured