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

问题描述:

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

I'm trying to read the ToolTip text from the system tray for an application that is not my own. Basically just what I figure will be the easiest way to pull some status information.

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

What would be the easiest way to pull the ToolTip text using C#?

让我们开始寻找托盘窗口句柄:

Let's start with finding systray window handle:

    [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 window is a toolbar class, you need to get information for a single icon:

    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;
    }

现在,你需要做的就是通过按钮迭代并获取数据:

Now, all you have to do is iterate through buttons and get data:

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

        }