开发者

Get ToolTip Text from Icon in System Tray

开发者 https://www.devze.com 2023-03-13 03:19 出处:网络
I\'m trying to read the ToolTip text from the system tray for an application that is not my own.Basicall开发者_运维百科y just what I figure will be the easiest way to pull some status information.

I'm trying to read the ToolTip text from the system tray for an application that is not my own. Basicall开发者_运维百科y just what I figure will be the easiest way to pull some status information.

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

        }


In case anyone comes across this thread and has the same need, I posted a thread asking how to properly implement the code example and received a lot of help, and a working solution here:

Trouble implementing code example using PInvoke Declarations

0

精彩评论

暂无评论...
验证码 换一张
取 消