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;
Copy Code
We also add a LVCOLUMN LvCol;
(global variable). The LVCOLUMN struct
consists of a few parameters:
typedef struct _LV_COLUMN {
UINT mask;
int fmt;
int cx;
LPTSTR pszText;
int cchTextMax;
int iSubItem;
} LV_COLUMN;
Now that we know about the struct
's members, let's initialize and use what we need: at the WM_INITDIALOG
message.
Memset(&LvCol,0,sizeof(LvCol));
LvCol.mask=LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
LvCol.cx=0x28;
LvCol.pszText="Item";
LvCol.cx=0x42;
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);
Now, let us put some columns (as much as you like):
SendMessage(hList,LVM_INSERTCOLUMN,0,(LPARAM)&LvCol);
LvCol.pszText="Sub Item1";
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);
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));
LvItem.mask=LVIF_TEXT;
LvItem.cchTextMax = 256;
LvItem.iItem=0;
LvItem.iSubItem=0;
LvItem.pszText="Item 0";
SendMessage(hList,LVM_INSERTITEM,0,(LPARAM)&LvItem);
for(i=1;i<=5;i++)
{
LvItem.iSubItem=i;
sprintf(Temp,"SubItem %d",i);
LvItem.pszText=Temp;
SendMessage(hList,LVM_SETITEM,0,(LPARAM)&LvItem);
}
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.