受欢迎的博客标签

SendMessage to ListView control in the across application( process) with c++

Published
 

Introduction

I've been trying to get the text of all items in listview another process (ListViewSystem32).

The another process (ListViewSystem32). run in 64 bit system

#include <commctrl.h>

 The LVITEM struct consists of a few parameters:

        /// <summary>
        /// LVITEM结构体,是列表视图控件的一个重要的数据结构
        /// 占空间:4(int)x7=28个byte
        /// </summary>

typedef struct _LV_ITEM {  
    UINT   mask;        // attributes of this data structure  For the example:lvItem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM|LVIF_STATE;说明此结构中哪些成员是有效的
    int    iItem;       // index of the item to which this structure refers  索引值(行号)从0开始
    int    iSubItem;    // index of the subitem to which this structure refers  子项的索引值(列号)从0开始
    UINT   state;       // Specifies the current state of the item   子项的状态
    UINT   stateMask;   // Specifies the bits of the state member that are valid.   态有效的屏蔽位
    LPTSTR  pszText;    // Pointer to a null-terminated string      项或子项的名称
                        // that contains the item text 
    int    cchTextMax;  // Size of the buffer pointed to by the pszText member   pszText所指向的缓冲区大小
    int    iImage;      // index of the list view item's icon 
    LPARAM lParam;      // 32-bit value to associate with item 
} LV_ITEM;
 

We also add a LVCOLUMN LvCol; (global variable). The LVCOLUMN struct consists of a few parameters:

 
typedef struct _LV_COLUMN {  
    UINT mask;       // which members of this structure contain valid information
    int fmt;         // alignment of the column heading and the subitem text 
    int cx;          // Specifies the width, in pixels, of the column.
    LPTSTR pszText;  // Pointer to a null-terminated string
                     // that contains the column heading 
    int cchTextMax;  // Specifies the size, in characters, of the buffer
    int iSubItem;    // index of subitem
} LV_COLUMN;

Now that we know about the struct's members, let's initialize and use what we need: at the WM_INITDIALOG message.

 
// Here we put the info on the Coulom headers
// this is not data, only name of each header we like
Memset(&LvCol,0,sizeof(LvCol));                  // Zero Members
LvCol.mask=LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;    // Type of mask
LvCol.cx=0x28;                                   // width between each coloum
LvCol.pszText="Item";                            // First Header Text
LvCol.cx=0x42;                                   // width of column

For more information that our list control can supply us, we can use the extended styles (full raw select):

 
SendMessage(hList,LVM_SETEXTENDEDLISTVIEWSTYLE,
           0,LVS_EX_FULLROWSELECT); // Set style

Now, let us put some columns (as much as you like):

 
// Inserting Couloms as much as we want
SendMessage(hList,LVM_INSERTCOLUMN,0,(LPARAM)&LvCol); // Insert/Show the coloum
LvCol.pszText="Sub Item1";                            // Next coloum
SendMessage(hList,LVM_INSERTCOLUMN,1,(LPARAM)&LvCol); // ...
LvCol.pszText="Sub Item2";                            //
SendMessage(hList,LVM_INSERTCOLUMN,2,(LPARAM)&LvCol); //
LvCol.pszText="Sub Item3";                            //
SendMessage(hList,LVM_INSERTCOLUMN,3,(LPARAM)&LvCol); //
LvCol.pszText="Sub Item4";                            //
SendMessage(hList,LVM_INSERTCOLUMN,4,(LPARAM)&LvCol); //
LvCol.pszText="Sub Item5";                            //
SendMessage(hList,LVM_INSERTCOLUMN,5,(LPARAM)&LvCol); // ...same as above

Once we've added headers (columns) to our listview, we need to add some items to it. This is done via the above mentioned LVITEM struct.

 
memset(&LvItem,0,sizeof(LvItem)); // Zero struct's Members

//  Setting properties Of members:

LvItem.mask=LVIF_TEXT;   // Text Style
LvItem.cchTextMax = 256; // Max size of test
LvItem.iItem=0;          // choose item  
LvItem.iSubItem=0;       // Put in first coluom
LvItem.pszText="Item 0"; // Text to display (can be from a char variable) (Items)

SendMessage(hList,LVM_INSERTITEM,0,(LPARAM)&LvItem); // Send info to the Listview

for(i=1;i<=5;i++) // Add SubItems in a loop
{
   LvItem.iSubItem=i;
   sprintf(Temp,"SubItem %d",i);
   LvItem.pszText=Temp;
   SendMessage(hList,LVM_SETITEM,0,(LPARAM)&LvItem); // Enter text to SubItems
}
 
 

 

We use all the messages that the listview has to offer us and from the code we used above, it wont be hard to get the item/sub items:

 
	
	//获得窗口所在进程ID
	//come from:https://stackoverflow.com/questions/12679518/win32-getting-listview-control-content-from-another-application
        DWORD dwProcessId;
	GetWindowThreadProcessId(hWndListView, &dwProcessId);

	// Open a handle to the remote process's kernel object  打开并插入进程
	HANDLE hProcess = OpenProcess(
		PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
		FALSE, dwProcessId);

	if (hProcess == NULL) {
		
		printf("Could not communicate with process\n");
		
	}


//itemCount=3520
	//returns CORRECT item count of the ListView Control
	//LV列表总行数
	int itemCount = SendMessage(hwndListView, LVM_GETITEMCOUNT, 0, 0);   // number of items



	//listview控件的列头句柄
	HWND headerhwnd = (HWND)SendMessage(hwndListView, LVM_GETHEADER, 0, 0);//listview的列头句柄   https://github.com/larygwil/FileZilla-proj/blob/d57cb7e1fa42945ed059317bc9cbb2b94438fd4d/FileZilla3/tags/3.10.0/src/interface/listctrlex.cpp

	//LV列表总列数
	int colCount = SendMessage(headerhwnd, HDM_GETITEMCOUNT, 0, 0);   // number of COLUM


	printf("SysListView32 ITEMCOUNT %d  %d\n", itemCount, colCount);

//You are allocating virtual memory for text. You must also allocate virtual memory for LVITEM. Then assign the text memory to lvItem.pszText, and then read both memory. It has to be compiled 64-bit for 64-bit systems. Add more error checks.
// see:https://stackoverflow.com/questions/35677119/windows-listview-lvm-getitem-iimage-is-always-zero

LV_ITEM* plvi = NULL;

// Allocate memory in the remote process's address space
	plvi = (LV_ITEM*)VirtualAllocEx(hProcess,
		NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

	if (plvi == NULL) {
		goto cleanup;
	}

// Get the ListView item's text data
	// Initialize a local LV_ITEM structure
	LV_ITEM lvi;
	memset(&lvi, 0, sizeof(LV_ITEM));
	lvi.mask = LVIF_TEXT;
	lvi.iItem = item;
	lvi.iSubItem = subItem;
	// NOTE: The text data immediately follows the LV_ITEM structure
	// in the memory block allocated in the remote process.
	lvi.pszText = (LPTSTR)(plvi + 1);
	lvi.cchTextMax = 100;

	// Write the local LV_ITEM structure to the remote memory block
	if (!WriteProcessMemory(hProcess, plvi, &lvi, sizeof(lvi), NULL)) {
		goto cleanup;
	}

	// Tell the ListView control to fill the remote LV_ITEM structure
	ListView_GetItem(hWndListView, plvi);

	// Read the remote text string into the end of our clipboard buffer
	if (!ReadProcessMemory(hProcess, plvi + 1, (LPVOID)&szReadBuffer, sizeof(szReadBuffer), NULL)) {
		goto cleanup;
	}

	*ppwszText = (TCHAR*)malloc(_tcslen(szReadBuffer) + sizeof(TCHAR));
	if (!*ppwszText) {
		goto cleanup;
	}

	retcode = true;
	//_tcscpy(*ppwszText, szReadBuffer);

	// ListView_SetItemState(hWndListView, -1, 0, LVIS_SELECTED);

cleanup:
	// Free the memory in the remote process's address space
	if (hProcess) {
		VirtualFreeEx(hProcess, plvi, 0, MEM_RELEASE);
		// Cleanup and put our results on the clipboard
		CloseHandle(hProcess);
	}
	return retcode;

Label Editing

Say we want to edit our item's text at runtime, how can we do it? We will use the LVN_BEGINLABELEDIT and LVN_ENDLABELEDIT messages.