这是我的代码:
public static string ReadListViewItem(IntPtr lstview, int item)
{
const int dwBufferSize = 1024;
int dwProcessID;
LV_ITEM lvItem;
string retval;
bool bSuccess;
IntPtr hProcess = IntPtr.Zero;
IntPtr lpRemoteBuffer = IntPtr.Zero;
IntPtr lpLocalBuffer = IntPtr.Zero;
IntPtr threadId = IntPtr.Zero;
try
{
lvItem = new LV_ITEM();
lpLocalBuffer = Marshal.AllocHGlobal(dwBufferSize);
// Get the process id owning the window
threadId = GetWindowThreadProcessId(lstview, out dwProcessID);
if ((threadId == IntPtr.Zero) || (dwProcessID == 0))
throw new ArgumentException("hWnd");
// Open the process with all access
hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID);
if (hProcess == IntPtr.Zero)
throw new ApplicationException("Failed to access process");
// Allocate a buffer in the remote process
lpRemoteBuffer = VirtualAllocEx(hProcess, IntPtr.Zero, dwBufferSize, MEM_COMMIT,
PAGE_READWRITE);
if (lpRemoteBuffer == IntPtr.Zero)
throw new SystemException("Failed to allocate memory in remote process");
// Fill in the LVITEM struct, this is in your own process
// Set the pszText member to somewhere in the remote buffer,
// For the example I used the address imediately following the LVITEM stuct
lvItem.mask = LVIF_TEXT;
lvItem.iItem = item;
lvItem.iSubItem = 2;
lvItem.pszText = (IntPtr)(lpRemoteBuffer.ToInt32() + Marshal.SizeOf(typeof(LV_ITEM)));
lvItem.cchTextMax = 50;
// Copy the local LVITEM to the remote buffer
bSuccess = WriteProcessMemory(hProcess, lpRemoteBuffer, ref lvItem,
Marshal.SizeOf(typeof(LV_ITEM)), IntPtr.Zero);
if (!bSuccess)
throw new SystemException("Failed to write to process memory");
// Send the message to the remote window with the address of the remote buffer
SendMessage(lstview, LVM_GETITEMText, 0, lpRemoteBuffer);
// Read the struct back from the remote process into local buffer
bSuccess = ReadProcessMemory(hProcess, lpRemoteBuffer, lpLocalBuffer, dwBufferSize,IntPtr.Zero);
if (!bSuccess)
throw new SystemException("Failed to read from process memory");
// At this point the lpLocalBuffer contains the returned LV_ITEM structure
// the next line extracts the text from the buffer into a managed string
retval = Marshal.PtrToStringAnsi((IntPtr)(lpLocalBuffer +
Marshal.SizeOf(typeof(LV_ITEM))));
}
finally
{
if (lpLocalBuffer != IntPtr.Zero)
Marshal.FreeHGlobal(lpLocalBuffer);
if (lpRemoteBuffer != IntPtr.Zero)
VirtualFreeEx(hProcess, lpRemoteBuffer, 0, MEM_RELEASE);
if (hProcess != IntPtr.Zero)
CloseHandle(hProcess);
}
return retval;
}
无论我做什么,retval 都会返回空,尽管 lpLocalBuffer 不会。
这是 ListItem 的定义:
[StructLayout(LayoutKind.Sequential)]
private struct LV_ITEM
{
public int mask;
public int iItem;
public int iSubItem;
public int state;
public int stateMask;
public IntPtr pszText;
public int cchTextMax;
public int iImage;
internal int lParam;
internal int iIndent;
}
我尝试为 86x、64 位、任何 cpu 进行编译,但似乎没有任何效果!
知道为什么会这样吗?
C# + .net4 , windows 7 64bit.
最佳答案
这是一种不同的方法 - 使用 UI Automation .它为您执行跨进程、跨位数工作,并且适用于 ListView 、列表框或几乎任何其他标准 Windows UI。这是一个示例应用程序,它将从鼠标指针下的 ListView 中获取 HWND,并将项目转储到其中。它只转储每个项目的名称;使用 Listviews,我认为您可以根据需要递归到每个项目中的字段。
// Compile using: csc ReadListView.cs /r:UIAutomationClient.dll
using System;
using System.Windows.Automation;
using System.Runtime.InteropServices;
class ReadListView
{
public static void Main()
{
Console.WriteLine("Place pointer over listview and hit return...");
Console.ReadLine();
// Get cursor position, then the window handle at that point...
POINT pt;
GetCursorPos(out pt);
IntPtr hwnd = WindowFromPoint(pt);
// Get the AutomationElement that represents the window handle...
AutomationElement el = AutomationElement.FromHandle(hwnd);
// Walk the automation element tree using content view, so we only see
// list items, not scrollbars and headers. (Use ControlViewWalker if you
// want to traverse those also.)
TreeWalker walker = TreeWalker.ContentViewWalker;
int i = 0;
for( AutomationElement child = walker.GetFirstChild(el) ;
child != null;
child = walker.GetNextSibling(child) )
{
// Print out the type of the item and its name
Console.WriteLine("item {0} is a \"{1}\" with name \"{2}\"", i++, child.Current.LocalizedControlType, child.Current.Name);
}
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
};
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(POINT pt);
[DllImport("user32.dll")]
private static extern int GetCursorPos(out POINT pt);
}
关于c# - 在 64 位中从 SysListView32 获取文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5369155/