c# - 在 64 位中从 SysListView32 获取文本

标签 c# winapi syslistview32

这是我的代码:

   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/

相关文章:

c# - 调试 Windows 服务 - 防止无法启动服务

c++ - IContextMenu3 HandleMenuMsg2 从未被调用

delphi - SysListView32类似鼠标选择矩形

c - 使用 C 枚举 SysListView32 项

c# - 如何将自定义 `UITableCell` 提供给 `UITableView`,使其具有与内置单元格相同的布局指标?

c# - 项目资源和本地资源图片的区别

c - win32/C对话框: "modern" look/style for a combo box

c# - 在 Parallel.ForEach 中嵌套 await

c++ - 从 ListView 中选择并突出显示项目