从其他窗口获取ListView项目

我正在做一些关于c#的项目。 我需要从ListView窗口获取i项目,通过做这样的事情我得到它的句柄

 IntPtr par_hWnd = API.FindWindow(null, "Form1"); IntPtr child1 = API.FindWindowEx(par_hWnd, (IntPtr)0, null, null); 

API是我的静态类,有很多来自“user32.dll”的dllimports我能够获得这个ListView中的项目数:

 IntPtr count = API.SendMessage(child1, API.LVM_GETITEMCOUNT, 0, 0); 

现在我需要获取item的文本,但结果必须放在LVITEM Structure中,我不知道如何正确调用SendMessage ,以及如何在c#中实现LVITEM 。 找不到c#的例子。 有帮助吗?

我找到了WinAPI的C#包装器,似乎可以从任何窗口访问LV的内容。
ManagedWinapi

 using ManagedWinapi.Windows; using System; namespace TestApp { class Program { static void Main(string[] args) { // Create a SystemWindow object from the HWND of the ListView SystemWindow lvWindow = new SystemWindow((IntPtr)0x6d1d38); // Create a ListView object from the SystemWindow object var lv = SystemListView.FromSystemWindow(lvWindow); // Read text from a row var text = lv[0].Title; } } } 

此外,我还在这里分叉mwapi并尝试添加一些新function – 主要围绕着色ListView行,但也添加了一些丢失的p / invokes等。

在外部进程中检索列表视图的内容是一件复杂的事情。 因为列表视图位于另一个进程中 ,并且LVM_GETITEM消息要求您发送LVITEM结构的指针,该指针必须在远程进程的内存堆中分配。

这是代码:

实施

 // 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); 

附录:最小的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); }