I'm doing some project on c#.
I need to get i
item from ListView
window, handle of it I got by doing something like this
IntPtr par_hWnd = API.FindWindow(null, "Form1");
IntPtr child1 = API.FindWindowEx(par_hWnd, (IntPtr)0, null, null);
API
is my static class with lots of dllimports from "user32.dll"
I am able to get count of items in this ListView:
IntPtr count = API.SendMessage(child1, API.LVM_GETITEMCOUNT, 0, 0);
Now i need to get the text of item, but the result somehow must be placed in the LVITEM
Structure, I don't know how to call SendMessage
correctly, and how to implement LVITEM
in c#. Can't find examples for c#. Any help?
The ListViewItem class defines the appearance, behavior, and data associated with an item that is displayed in the ListView control. ListViewItem objects can be displayed in the ListView control in one of four different views. Items can be displayed as large or small icons or as small icons in a vertical list.
In ListBox we can get selected item by a simple line of code: listbox1. SelectedItem .
Use the RemoveAt or Clear method of the Items property. The RemoveAt method removes a single item; the Clear method removes all items from the list.
To retrieve the content of a list view in a foreign process is a complicated thing. Because the list view is in another process, and the LVM_GETITEM
message requires you to send a pointer of an LVITEM
structure, which must be allocated in the remote process's memory heap.
Here is the code:
// firstly we have the handle to the list view:
var listViewPtr = this.GetListViewHandle();
// get the ID of the process who owns the list view
WinAPI.GetWindowThreadProcessId(listViewPtr, out var processId);
// open the process
var processHandle = WinAPI.OpenProcess(
WinAPI.ProcessAccessFlags.VirtualMemoryOperation
| WinAPI.ProcessAccessFlags.VirtualMemoryRead
| WinAPI.ProcessAccessFlags.VirtualMemoryWrite,
false,
processId);
// allocate buffer for a string to store the text of the list view item we wanted
var textBufferPtr = WinAPI.VirtualAllocEx(
processHandle,
IntPtr.Zero,
WinAPI.MAX_LVMSTRING,
WinAPI.AllocationType.Commit,
WinAPI.MemoryProtection.ReadWrite);
var itemId = 0; // the item (row) index
var subItemId = 1; // the subitem (column) index
// this is the LVITEM we need to inject
var lvItem = new WinAPI.LVITEM
{
mask = (uint)WinAPI.ListViewItemFilters.LVIF_TEXT,
cchTextMax = (int)WinAPI.MAX_LVMSTRING,
pszText = textBufferPtr,
iItem = itemId,
iSubItem = subItemId
};
// allocate memory for the LVITEM structure in the remote process
var lvItemSize = Marshal.SizeOf(lvItem);
var lvItemBufferPtr = WinAPI.VirtualAllocEx(
processHandle,
IntPtr.Zero,
(uint)lvItemSize,
WinAPI.AllocationType.Commit,
WinAPI.MemoryProtection.ReadWrite);
// to inject the LVITEM structure, we have to use the WriteProcessMemory API, which does a pointer-to-pointer copy. So we need to turn the managed LVITEM structure to an unmanaged LVITEM pointer
// first allocate a piece of unmanaged memory ...
var lvItemLocalPtr = Marshal.AllocHGlobal(lvItemSize);
// ... then copy the managed object into the unmanaged memory
Marshal.StructureToPtr(lvItem, lvItemLocalPtr, false);
// and write into remote process's memory
WinAPI.WriteProcessMemory(
processHandle,
lvItemBufferPtr,
lvItemLocalPtr,
(uint)lvItemSize,
out var _);
// tell the list view to fill in the text we desired
WinAPI.SendMessage(listViewPtr, (int)WinAPI.ListViewMessages.LVM_GETITEMTEXT, itemId, lvItemBufferPtr);
// read the text. we allocate a managed byte array to store the retrieved text instead of AllocHGlobal-ing a piece of unmanaged memory, because CLR knows how to marshal between a pointer and a byte array
var localTextBuffer = new byte[WinAPI.MAX_LVMSTRING];
WinAPI.ReadProcessMemory(
processHandle,
textBufferPtr,
localTextBuffer,
(int)WinAPI.MAX_LVMSTRING,
out var _);
// convert the byte array to a string. assume the remote process uses Unicode
var text = Encoding.Unicode.GetString(localTextBuffer);
// the trailing zeros are not cleared automatically
text = text.Substring(0, text.IndexOf('\0'));
// finally free all the memory we allocated, and close the process handle we opened
WinAPI.VirtualFreeEx(processHandle, textBufferPtr, 0, WinAPI.AllocationType.Release);
WinAPI.VirtualFreeEx(processHandle, lvItemBufferPtr, 0, WinAPI.AllocationType.Release);
Marshal.FreeHGlobal(lvItemLocalPtr);
WinAPI.CloseHandle(processHandle);
static class WinAPI
{
public enum ListViewMessages
{
LVM_GETITEMTEXT = 0x104B
}
public enum ListViewItemFilters : uint
{
LVIF_TEXT = 0x0001,
}
public const uint MAX_LVMSTRING = 255;
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct LVITEM
{
public uint mask;
public int iItem;
public int iSubItem;
public uint state;
public uint stateMask;
public IntPtr pszText;
public int cchTextMax;
public int iImage;
public IntPtr lParam;
}
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId);
[Flags]
public enum ProcessAccessFlags : uint
{
VirtualMemoryOperation = 0x0008,
VirtualMemoryRead = 0x0010,
VirtualMemoryWrite = 0x0020,
}
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[Flags]
public enum AllocationType
{
Commit = 0x1000,
Release = 0x8000,
}
[Flags]
public enum MemoryProtection
{
ReadWrite = 0x0004,
}
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, uint processId);
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr hHandle);
[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, out int lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] buffer, int dwSize, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With