从系统托盘中的图标获取工具提示文本

本文关键字:图标 获取 工具提示 文本 系统 | 更新日期: 2023-09-27 17:59:27

我正试图从系统托盘中读取非我自己的应用程序的工具提示文本。基本上,我认为这将是获取一些状态信息的最简单方法。

使用C#提取工具提示文本的最简单方法是什么?

从系统托盘中的图标获取工具提示文本

让我们从查找systray窗口句柄开始:

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpClassName, string lpWindowName);
    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    static IntPtr GetSystemTrayHandle()
    {
        IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
        if (hWndTray != IntPtr.Zero)
        {
            hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "TrayNotifyWnd", null);
            if (hWndTray != IntPtr.Zero)
            {
                hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "SysPager", null);
                if (hWndTray != IntPtr.Zero)
                {
                    hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "ToolbarWindow32", null);
                    return hWndTray;
                }
            }
        }
        return IntPtr.Zero;
    }

Systray窗口是一个工具栏类,您需要获得单个图标的信息:

    private static unsafe bool GetTBButton(IntPtr hToolbar, int i, ref TBBUTTON tbButton, ref string text, ref IntPtr ipWindowHandle)
    {
        // One page
        const int BUFFER_SIZE = 0x1000;
        byte[] localBuffer = new byte[BUFFER_SIZE];
        UInt32 processId = 0;
        UInt32 threadId = User32.GetWindowThreadProcessId(hToolbar, out processId);
        IntPtr hProcess = Kernel32.OpenProcess(ProcessRights.ALL_ACCESS, false, processId);
        if (hProcess == IntPtr.Zero) { Debug.Assert(false); return false; }
        IntPtr ipRemoteBuffer = Kernel32.VirtualAllocEx(
            hProcess,
            IntPtr.Zero,
            new UIntPtr(BUFFER_SIZE),
            MemAllocationType.COMMIT,
            MemoryProtection.PAGE_READWRITE);
        if (ipRemoteBuffer == IntPtr.Zero) { Debug.Assert(false); return false; }
        // TBButton
        fixed (TBBUTTON* pTBButton = &tbButton)
        {
            IntPtr ipTBButton = new IntPtr(pTBButton);
            int b = (int)User32.SendMessage(hToolbar, TB.GETBUTTON, (IntPtr)i, ipRemoteBuffer);
            if (b == 0) { Debug.Assert(false); return false; }
            // this is fixed
            Int32 dwBytesRead = 0;
            IntPtr ipBytesRead = new IntPtr(&dwBytesRead);
            bool b2 = Kernel32.ReadProcessMemory(
                hProcess,
                ipRemoteBuffer,
                ipTBButton,
                new UIntPtr((uint)sizeof(TBBUTTON)),
                ipBytesRead);
            if (!b2) { Debug.Assert(false); return false; }
        }
        // button text
        fixed (byte* pLocalBuffer = localBuffer)
        {
            IntPtr ipLocalBuffer = new IntPtr(pLocalBuffer);
            int chars = (int)User32.SendMessage(hToolbar, TB.GETBUTTONTEXTW, (IntPtr)tbButton.idCommand, ipRemoteBuffer);
            if (chars == -1) { Debug.Assert(false); return false; }
            // this is fixed
            Int32 dwBytesRead = 0;
            IntPtr ipBytesRead = new IntPtr(&dwBytesRead);
            bool b4 = Kernel32.ReadProcessMemory(
                hProcess,
                ipRemoteBuffer,
                ipLocalBuffer,
                new UIntPtr(BUFFER_SIZE),
                ipBytesRead);
            if (!b4) { Debug.Assert(false); return false; }
            text = Marshal.PtrToStringUni(ipLocalBuffer, chars);
            if (text == " ") text = String.Empty;
        }
        Kernel32.VirtualFreeEx(
            hProcess,
            ipRemoteBuffer,
            UIntPtr.Zero,
            MemAllocationType.RELEASE);
        Kernel32.CloseHandle(hProcess);
        return true;
    }

现在,您所要做的就是遍历按钮并获取数据:

        IntPtr _ToolbarWindowHandle = GetSystemTrayHandle();
        UInt32 count = User32.SendMessage(_ToolbarWindowHandle, TB.BUTTONCOUNT, 0, 0);
        for (int i = 0; i < count; i++)
        {
            TBBUTTON tbButton = new TBBUTTON();
            string text = String.Empty;
            IntPtr ipWindowHandle = IntPtr.Zero;
            bool b = GetTBButton(_ToolbarWindowHandle, i, ref tbButton, ref text, ref ipWindowHandle);
        }

如果有人遇到这个线程并有同样的需求,我发布了一个线程,询问如何正确实现代码示例,并收到了很多帮助,以及一个有效的解决方案:

使用PInvoke Declarations 实现代码示例时出现问题