在外部进程中检索列表视图的内容是一件复杂的事情。因为列表视图位于另一个进程中,而LVM_GETITEM
消息需要您发送指向LVITEM
结构的指针,该结构必须在远程进程的内存堆中分配。
以下是代码:
实现
var listViewPtr = this.GetListViewHandle();
WinAPI.GetWindowThreadProcessId(listViewPtr, out var processId);
var processHandle = WinAPI.OpenProcess(
WinAPI.ProcessAccessFlags.VirtualMemoryOperation
| WinAPI.ProcessAccessFlags.VirtualMemoryRead
| WinAPI.ProcessAccessFlags.VirtualMemoryWrite,
false,
processId);
var textBufferPtr = WinAPI.VirtualAllocEx(
processHandle,
IntPtr.Zero,
WinAPI.MAX_LVMSTRING,
WinAPI.AllocationType.Commit,
WinAPI.MemoryProtection.ReadWrite);
var itemId = 0;
var subItemId = 1;
var lvItem = new WinAPI.LVITEM
;
var lvItemSize = Marshal.SizeOf(lvItem);
var lvItemBufferPtr = WinAPI.VirtualAllocEx(
processHandle,
IntPtr.Zero,
(uint)lvItemSize,
WinAPI.AllocationType.Commit,
WinAPI.MemoryProtection.ReadWrite);
var lvItemLocalPtr = Marshal.AllocHGlobal(lvItemSize);
Marshal.StructureToPtr(lvItem, lvItemLocalPtr, false);
WinAPI.WriteProcessMemory(
processHandle,
lvItemBufferPtr,
lvItemLocalPtr,
(uint)lvItemSize,
out var _);
WinAPI.SendMessage(listViewPtr, (int)WinAPI.ListViewMessages.LVM_GETITEMTEXT, itemId, lvItemBufferPtr);
var localTextBuffer = new byte[WinAPI.MAX_LVMSTRING];
WinAPI.ReadProcessMemory(
processHandle,
textBufferPtr,
localTextBuffer,
(int)WinAPI.MAX_LVMSTRING,
out var _);
var text = Encoding.Unicode.GetString(localTextBuffer);
text = text.Substring(0, text.IndexOf('\0'));
WinAPI.VirtualFreeEx(processHandle, textBufferPtr, 0, WinAPI.AllocationType.Release);
WinAPI.VirtualFreeEx(processHandle, lvItemBufferPtr, 0, WinAPI.AllocationType.Release);
Marshal.FreeHGlobal(lvItemLocalPtr);
WinAPI.CloseHandle(processHandle);
附录:最小化的Windows API声明
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);
}
Marshal.PtrToStringAuto
进行简化。 - Martin Prikryl