从其他Windows应用程序获取listview项始终返回空字符串

时间:2017-05-24 10:43:30

标签: c#

我正在制作winform应用程序,需要从其他具有多个选项卡的Windows应用程序获取listview的内容,每个选项卡都包含一个列表视图,如Windows任务管理器。

我正在关注此Q& A Get ListView items from other windows和本指南Crossing the process boundry with .NET。 不幸的是,我真的是win32api的新手。我总是从本地缓冲区返回空字符串。

到目前为止,我的代码如下。

    public partial class Form1 : Form
    {
        private const int LVM_FIRST = 0x1000;
        private const int LVM_GETITEMCOUNT = LVM_FIRST + 4;
        private const int LVM_GETITEM = LVM_FIRST + 75;
        private const int LVIF_TEXT = 0x0001;
        private const int LVM_SETITEM = 0x1006;
        private const uint PROCESS_ALL_ACCESS = (uint)(0x000F0000L | 0x00100000L | 0xFFF);
        private const uint MEM_COMMIT = 0x1000;
        private const uint MEM_RELEASE = 0x8000;
        private const uint PAGE_READWRITE = 0x04;

        public Form1()
        {
            InitializeComponent();
        }

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

        [DllImport("user32.dll")]
        static extern bool SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32")]
        static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out int lpwdProcessID);

        [DllImport("kernel32")]
        static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);

        [DllImport("kernel32")]
        static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flAllocationType, uint flProtect);

        [DllImport("kernel32")]
        static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint dwFreeType);

        [DllImport("kernel32")]
        static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref LV_ITEM buffer, int dwSize, IntPtr lpNumberOfBytesWritten);

        [DllImport("kernel32")]
        static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int dwSize, IntPtr lpNumberOfBytesRead);

        [DllImport("kernel32")]
        static extern bool CloseHandle(IntPtr hObject);

        [StructLayout(LayoutKind.Sequential)]
        public struct LV_ITEM
        {
            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 static string ReadListViewItem(IntPtr hWnd, 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(hWnd, out dwProcessID);
                if ((threadId == IntPtr.Zero) || (dwProcessID == 0))
                    throw new ArgumentException("Invalid 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.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(hWnd, LVM_GETITEM, 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.PtrToStringAuto((IntPtr (lpLocalBuffer.ToInt32() + 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;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var mainWnd = FindWindow(null, "Windows Task Manager");
            var childWnd = FindWindowEx(mainWnd, IntPtr.Zero, null, "Processes");

            IntPtr count = SendMessage(mainWnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
            Console.WriteLine(count);

            Console.WriteLine(ReadListViewItem(mainWnd, 1));
        }
    }

拜托,有人给我建议!!

非常感谢!

0 个答案:

没有答案