如何获取具有系统托盘图标的进程

2023-12-24

我正在尝试创建获取具有系统托盘图标的进程列表的应用程序。
我进行了大量搜索并找到了一些参考资料:

  1. http://www.raymond.cc/blog/find-out-what-program-are-running-at-windows-system-tray/ http://www.raymond.cc/blog/find-out-what-program-are-running-at-windows-system-tray/

  2. https://superuser.com/questions/708674/how-to-find-out-what-process-a-system-tray-icon-corresponds-to https://superuser.com/questions/708674/how-to-find-out-what-process-a-system-tray-icon-corresponds-to

  3. 哪个 Windows 进程正在显示给定的任务栏系统托盘图标? https://stackoverflow.com/questions/5166551/which-windows-process-is-displaying-a-given-taskbar-system-tray-icon

  4. https://social.msdn.microsoft.com/Forums/vstudio/en-US/53e27f60-37af-406f-bbdc-45db2bd3dee6/how-to-find-a-system-tray-process https://social.msdn.microsoft.com/Forums/vstudio/en-US/53e27f60-37af-406f-bbdc-45db2bd3dee6/how-to-find-a-system-tray-process

  5. https://social.msdn.microsoft.com/Forums/vstudio/en-US/4c4f60ce-3573-433d-994e-9c17f95187f0/finding-which-applications-and-services-are-listed-in-the-system-托盘?论坛=csharpgeneral https://social.msdn.microsoft.com/Forums/vstudio/en-US/4c4f60ce-3573-433d-994e-9c17f95187f0/finding-which-applications-and-services-are-listed-in-the-system-tray?forum=csharpgeneral

  6. http://www.codeproject.com/Articles/10497/A-tool-to-order-the-window-buttons-in-your-taskbar http://www.codeproject.com/Articles/10497/A-tool-to-order-the-window-buttons-in-your-taskbar

  7. 从系统托盘中的图标获取工具提示文本 https://stackoverflow.com/questions/6366505/get-tooltip-text-from-icon-in-system-tray

所有这些都是很好的资源,但对我来说信息最丰富的是 3 和 4。

In 1 http://www.raymond.cc/blog/find-out-what-program-are-running-at-windows-system-tray/我们有一个我想要的例子。

I want the list of processes that have systray icon:
enter image description here Example for application called "AnVir Task Manager"

Using the code from link 6 http://www.codeproject.com/Articles/10497/A-tool-to-order-the-window-buttons-in-your-taskbar I succeed to iterate through the systray buttons and see the text of each button:
enter image description here

但我不确定如何找到与每个托盘图标相关的进程。

In code project he mentioned that the information that can help identify the process is the dwData but the problem is that when I found button that appears in Systray, its dwData = 0:
enter image description here

Code:

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SystrayIcons
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            Engine.findProcessInSystray();
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Engine.findProcessInSystray();
        }
    }
}

引擎.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Common;
using System.Diagnostics;
using System.Collections;

namespace SystrayIcons
{

    static class Engine
    {
        static public void findProcessInSystray()
        {
            IntPtr systemTrayHandle = GetSystemTrayHandle();

            UInt32 count = User32.SendMessage(systemTrayHandle, TB.BUTTONCOUNT, 0, 0);

            ArrayList tbButtons = new ArrayList();
            List<TBBUTTON> tbButtons2 = new  List<TBBUTTON>();

            for (int i = 0; i < count; i++)
            {
                TBBUTTON tbButton = new TBBUTTON();
                string text = String.Empty;
                IntPtr ipWindowHandle = IntPtr.Zero;

                bool b = GetTBButton(systemTrayHandle, i, ref tbButton, ref text, ref ipWindowHandle);
               // if (tbButton.iBitmap != 0) 
               if(tbButton.dwData != 0)
                {
                    tbButtons.Add(tbButton);
                    tbButtons2.Add(tbButton);
                }
            }



           // CreateImageList();

            System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
            foreach (System.Diagnostics.Process process in processes)
            {
                if (process.MainWindowHandle == systemTrayHandle)
                {

                }

            }



        }

        static IntPtr GetSystemTrayHandle()
        {
            IntPtr hWndTray = User32.FindWindow("Shell_TrayWnd", null);
            if (hWndTray != IntPtr.Zero)
            {
                hWndTray = User32.FindWindowEx(hWndTray, IntPtr.Zero, "TrayNotifyWnd", null);
                if (hWndTray != IntPtr.Zero)
                {
                    hWndTray = User32.FindWindowEx(hWndTray, IntPtr.Zero, "SysPager", null);
                    if (hWndTray != IntPtr.Zero)
                    {
                        hWndTray = User32.FindWindowEx(hWndTray, IntPtr.Zero, "ToolbarWindow32", null);
                        return hWndTray;
                    }
                }
            }

            return IntPtr.Zero;
        }


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



// window handle
            fixed (byte* pLocalBuffer = localBuffer)
            {
                IntPtr ipLocalBuffer = new IntPtr(pLocalBuffer);

                // this is in the remote virtual memory space
                IntPtr ipRemoteData = new IntPtr(tbButton.dwData);

                // this is fixed
                Int32 dwBytesRead = 0;
                IntPtr ipBytesRead = new IntPtr(&dwBytesRead);

                bool b4 = Kernel32.ReadProcessMemory(
                    hProcess,
                    ipRemoteData,
                    ipLocalBuffer,
                    new UIntPtr(4),
                    ipBytesRead);

                if (!b4) { Debug.Assert(false); return false; }

                if (dwBytesRead != 4) { Debug.Assert(false); return false; }

                Int32 iWindowHandle = BitConverter.ToInt32(localBuffer, 0);
                if (iWindowHandle == -1) { Debug.Assert(false); }//return false; }

                ipWindowHandle = new IntPtr(iWindowHandle);
            }

            Kernel32.VirtualFreeEx(
                hProcess,
                ipRemoteBuffer,
                UIntPtr.Zero,
                MemAllocationType.RELEASE);


            Kernel32.CloseHandle(hProcess);
            return true;
        }

    }
}

Kernel32.cs

using System;
using System.Runtime.InteropServices;

namespace Common
{

//-----------------------------------------------------------------------------
// Structures

    [StructLayout(LayoutKind.Sequential)]
    internal struct SYSTEM_INFO 
    {
        public _PROCESSOR_INFO_UNION uProcessorInfo;
        public uint dwPageSize;
        public uint lpMinimumApplicationAddress;
        public uint lpMaximumApplicationAddress;
        public uint dwActiveProcessorMask;
        public uint dwNumberOfProcessors;
        public uint dwProcessorType;
        public uint dwAllocationGranularity;
        public uint dwProcessorLevel;
        public uint dwProcessorRevision;
    }

    [StructLayout(LayoutKind.Explicit)]
    internal struct _PROCESSOR_INFO_UNION
    {
        [FieldOffset(0)]
        public uint dwOemId;
        [FieldOffset(0)]
        public ushort wProcessorArchitecture;
        [FieldOffset(2)]
        public ushort wReserved;
    }

    [ StructLayout( LayoutKind.Sequential )]
    internal struct BY_HANDLE_FILE_INFORMATION
    {
        public UInt32 dwFileAttributes;
        public FILETIME ftCreationTime;
        public FILETIME ftLastAccessTime;
        public FILETIME ftLastWriteTime;
        public UInt32 dwVolumeSerialNumber;
        public UInt32 nFileSizeHigh;
        public UInt32 nFileSizeLow;
        public UInt32 nNumberOfLinks;
        public UInt32 nFileIndexHigh;
        public UInt32 nFileIndexLow;
    }

    [ StructLayout( LayoutKind.Sequential )]
    internal class MEMORYSTATUSEX
    {
        public Int32 Length;
        public Int32 MemoryLoad;
        public UInt64 TotalPhysical;
        public UInt64 AvailablePhysical;
        public UInt64 TotalPageFile;
        public UInt64 AvailablePageFile;
        public UInt64 TotalVirtual;
        public UInt64 AvailableVirtual;
        public UInt64 AvailableExtendedVirtual;

        public MEMORYSTATUSEX() { Length = Marshal.SizeOf( this ); }

        private void StopTheCompilerComplaining()
        {
            Length = 0;
            MemoryLoad = 0;
            TotalPhysical = 0;
            AvailablePhysical = 0;
            TotalPageFile = 0;
            AvailablePageFile = 0;
            TotalVirtual = 0;
            AvailableVirtual = 0;
            AvailableExtendedVirtual = 0;
        }
    }

//-----------------------------------------------------------------------------
// Constants

    internal class ProcessRights
    {
        public const UInt32 TERMINATE         = 0x0001  ;
        public const UInt32 CREATE_THREAD     = 0x0002  ;
        public const UInt32 SET_SESSIONID     = 0x0004  ;
        public const UInt32 VM_OPERATION      = 0x0008  ;
        public const UInt32 VM_READ           = 0x0010  ;
        public const UInt32 VM_WRITE          = 0x0020  ;
        public const UInt32 DUP_HANDLE        = 0x0040  ;
        public const UInt32 CREATE_PROCESS    = 0x0080  ;
        public const UInt32 SET_QUOTA         = 0x0100  ;
        public const UInt32 SET_INFORMATION   = 0x0200  ;
        public const UInt32 QUERY_INFORMATION = 0x0400  ;
        public const UInt32 SUSPEND_RESUME    = 0x0800  ;

        private const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
        private const UInt32 SYNCHRONIZE              = 0x00100000;

        public const UInt32 ALL_ACCESS        = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF;
    }

    internal class MemoryProtection
    {
        public const UInt32 PAGE_NOACCESS          =  0x01     ;
        public const UInt32 PAGE_READONLY          =  0x02     ;
        public const UInt32 PAGE_READWRITE         =  0x04     ;
        public const UInt32 PAGE_WRITECOPY         =  0x08     ;
        public const UInt32 PAGE_EXECUTE           =  0x10     ;
        public const UInt32 PAGE_EXECUTE_READ      =  0x20     ;
        public const UInt32 PAGE_EXECUTE_READWRITE =  0x40     ;
        public const UInt32 PAGE_EXECUTE_WRITECOPY =  0x80     ;
        public const UInt32 PAGE_GUARD             = 0x100     ;
        public const UInt32 PAGE_NOCACHE           = 0x200     ;
        public const UInt32 PAGE_WRITECOMBINE      = 0x400     ;
    }

    internal class MemAllocationType
    {
        public const UInt32 COMMIT       =     0x1000     ;
        public const UInt32 RESERVE      =     0x2000     ;
        public const UInt32 DECOMMIT     =     0x4000     ;
        public const UInt32 RELEASE      =     0x8000     ;
        public const UInt32 FREE         =    0x10000     ;
        public const UInt32 PRIVATE      =    0x20000     ;
        public const UInt32 MAPPED       =    0x40000     ;
        public const UInt32 RESET        =    0x80000     ;
        public const UInt32 TOP_DOWN     =   0x100000     ;
        public const UInt32 WRITE_WATCH  =   0x200000     ;
        public const UInt32 PHYSICAL     =   0x400000     ;
        public const UInt32 LARGE_PAGES  = 0x20000000     ;
        public const UInt32 FOURMB_PAGES = 0x80000000     ;
    }

    [Flags]
    public enum EFileAccess : uint
    {
        GenericRead = 0x80000000,
        GenericWrite = 0x40000000,
        GenericExecute = 0x20000000,
        GenericAll = 0x10000000,
    }

    [Flags]
    public enum EFileShare : uint
    {
        None = 0x00000000,
        Read = 0x00000001,
        Write = 0x00000002,
        Delete = 0x00000004,
    }

    public enum ECreationDisposition : uint
    {
        New = 1,
        CreateAlways = 2,
        OpenExisting = 3,
        OpenAlways = 4,
        TruncateExisting = 5,
    }

    [Flags]
    public enum EFileAttributes : uint
    {
        Readonly = 0x00000001,
        Hidden = 0x00000002,
        System = 0x00000004,
        Directory = 0x00000010,
        Archive = 0x00000020,
        Device = 0x00000040,
        Normal = 0x00000080,
        Temporary = 0x00000100,
        SparseFile = 0x00000200,
        ReparsePoint = 0x00000400,
        Compressed = 0x00000800,
        Offline= 0x00001000,
        NotContentIndexed = 0x00002000,
        Encrypted = 0x00004000,
        Write_Through = 0x80000000,
        Overlapped = 0x40000000,
        NoBuffering = 0x20000000,
        RandomAccess = 0x10000000,
        SequentialScan = 0x08000000,
        DeleteOnClose = 0x04000000,
        BackupSemantics = 0x02000000,
        PosixSemantics = 0x01000000,
        OpenReparsePoint = 0x00200000,
        OpenNoRecall = 0x00100000,
        FirstPipeInstance = 0x00080000
    }




//-----------------------------------------------------------------------------
// Functions

    internal class Kernel32
    {
        [DllImport("kernel32.dll")]
        public static extern void GetSystemInfo(
            out SYSTEM_INFO lpSystemInfo );


        [ DllImport( "Kernel32.dll" ) ]
        public static extern bool GetFileInformationByHandle
        (
            IntPtr hFile,
            out BY_HANDLE_FILE_INFORMATION lpFileInformation
        );

        [ DllImport( "kernel32.dll", SetLastError = true ) ]
        public static extern IntPtr CreateFile(
            string lpFileName,
            EFileAccess dwDesiredAccess,
            EFileShare dwShareMode,
            IntPtr lpSecurityAttributes,
            ECreationDisposition dwCreationDisposition,
            EFileAttributes dwFlagsAndAttributes,
            IntPtr hTemplateFile );


        [ DllImport( "Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode ) ]
        public static extern bool CreateHardLink
        (
            string FileName,
            string ExistingFileName,
            IntPtr lpSecurityAttributes
        );

        [ DllImport( "Kernel32.dll" ) ]
        public static extern bool Beep
        (
            UInt32 frequency,
            UInt32 duration
        );

        [ DllImport( "Kernel32.dll", SetLastError = true ) ]
        public static extern IntPtr OpenProcess(
            uint dwDesiredAccess,
            bool bInheritHandle,
            uint dwProcessId );

        [DllImport( "kernel32.dll", SetLastError = true ) ]
        public static extern IntPtr VirtualAllocEx(
            IntPtr hProcess,
            IntPtr lpAddress,
            UIntPtr dwSize,
            uint flAllocationType,
            uint flProtect);

        [DllImport("kernel32.dll")]
        public static extern bool ReadProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            IntPtr lpBuffer,
            UIntPtr nSize,
            IntPtr lpNumberOfBytesRead );

        [DllImport("kernel32.dll")]
        public static extern bool VirtualFreeEx(
            IntPtr hProcess,
            IntPtr lpAddress,
            UIntPtr dwSize,
            UInt32 dwFreeType );

        [DllImport("kernel32.dll")]
        public static extern bool GlobalMemoryStatusEx(
            MEMORYSTATUSEX buffer );


        [ DllImport( "kernel32.dll", SetLastError = true ) ]
        public static extern bool CloseHandle(
            IntPtr hObject );

    }

//-----------------------------------------------------------------------------

}

User32.cs

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Common
{
    internal enum GW : uint
    {
        HWNDFIRST        = 0,
        HWNDLAST         = 1,
        HWNDNEXT         = 2,
        HWNDPREV         = 3,
        OWNER            = 4,
        CHILD            = 5,
        MAX              = 6
    }

    internal class ICON
    {
        public const UInt32 SMALL          = 0;
        public const UInt32 BIG            = 1;
        public const UInt32 SMALL2         = 2; // XP+
    }

    internal enum MB : uint
    {
        SimpleBeep      = 0xFFFFFFFF,
        IconAsterisk    = 0x00000040,
        IconWarning     = 0x00000030,
        IconError       = 0x00000010,
        IconQuestion    = 0x00000020,
        OK              = 0x00000000
    }

    internal class SW
    {
        public const int HIDE               = 0;
        public const int SHOWNORMAL         = 1;
        public const int NORMAL             = 1;
        public const int SHOWMINIMIZED      = 2;
        public const int SHOWMAXIMIZED      = 3;
        public const int MAXIMIZE           = 3;
        public const int SHOWNOACTIVATE     = 4;
        public const int SHOW               = 5;
        public const int MINIMIZE           = 6;
        public const int SHOWMINNOACTIVE    = 7;
        public const int SHOWNA             = 8;
        public const int RESTORE            = 9;
        public const int SHOWDEFAULT        = 10;
        public const int FORCEMINIMIZE      = 11;
        public const int MAX                = 11;
    }

    internal class TB
    {
        public const uint GETBUTTON       = WM.USER + 23 ;
        public const uint BUTTONCOUNT     = WM.USER + 24 ;
        public const uint CUSTOMIZE       = WM.USER + 27 ;
        public const uint GETBUTTONTEXTA  = WM.USER + 45 ;
        public const uint GETBUTTONTEXTW  = WM.USER + 75 ;
    }

    internal class TBSTATE
    {
        public const uint CHECKED        =  0x01 ;
        public const uint PRESSED        =  0x02 ;
        public const uint ENABLED        =  0x04 ;
        public const uint HIDDEN         =  0x08 ;
        public const uint INDETERMINATE  =  0x10 ;
        public const uint WRAP           =  0x20 ;
        public const uint ELLIPSES       =  0x40 ;
        public const uint MARKED         =  0x80 ;
    }

    internal class WM
    {
        public const uint CLOSE   = 0x0010;
        public const uint GETICON = 0x007F;
        public const uint KEYDOWN = 0x0100;
        public const uint COMMAND = 0x0111;
        public const uint USER    = 0x0400; // 0x0400 - 0x7FFF
        public const uint APP     = 0x8000; // 0x8000 - 0xBFFF
    }

    internal class GCL
    {
        public const int MENUNAME       = - 8;
        public const int HBRBACKGROUND  = -10;
        public const int HCURSOR        = -12;
        public const int HICON          = -14;
        public const int HMODULE        = -16;
        public const int CBWNDEXTRA     = -18;
        public const int CBCLSEXTRA     = -20;
        public const int WNDPROC        = -24;
        public const int STYLE          = -26;
        public const int ATOM           = -32;
        public const int HICONSM        = -34;

        // GetClassLongPtr ( 64-bit )
        private const int GCW_ATOM           = -32;
        private const int GCL_CBCLSEXTRA     = -20;
        private const int GCL_CBWNDEXTRA     = -18;
        private const int GCLP_MENUNAME      = - 8;
        private const int GCLP_HBRBACKGROUND = -10;
        private const int GCLP_HCURSOR       = -12;
        private const int GCLP_HICON         = -14;
        private const int GCLP_HMODULE       = -16;
        private const int GCLP_WNDPROC       = -24;
        private const int GCLP_HICONSM       = -34;
        private const int GCL_STYLE          = -26;

    }

    [ StructLayout( LayoutKind.Sequential ) ]
    internal struct TBBUTTON 
    {
        public Int32 iBitmap;
        public Int32 idCommand;
        public byte fsState;
        public byte fsStyle;
//      [ MarshalAs( UnmanagedType.ByValArray, SizeConst=2 ) ]
//      public byte[] bReserved;
        public byte bReserved1;
        public byte bReserved2;
        public UInt32 dwData;
        public IntPtr iString;
    };

    internal class User32
    {
        private User32() {}

//      public const UInt32 WM_USER = 0x0400;

//      public const UInt32 WM_KEYDOWN = 0x0100;
        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(
            IntPtr hWnd,
            UInt32 msg,
            IntPtr wParam,
            IntPtr lParam );

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

        [ DllImport( "User32.dll" ) ]
        public static extern bool PostMessage
        (
            IntPtr hWnd,
            UInt32 Msg,
            IntPtr wParam,
            IntPtr lParam
        );

        [ DllImport( "User32.dll" ) ]
        public static extern bool PostMessage
        (
            IntPtr hWnd,
            UInt32 Msg,
            UInt32 wParam,
            UInt32 lParam
        );

        [ DllImport( "User32.dll" ) ]
        public static extern bool MessageBeep
        (
            MB BeepType
        );

        [DllImport("user32.dll")]
        public static extern bool ShowWindow
        (
            IntPtr hWnd,
            int nCmdShow
        );

        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow
        (
            IntPtr hWnd
        );


        [ DllImport( "User32.dll" ) ]
        public static extern IntPtr GetDesktopWindow
        (
        );

        [ DllImport( "user32.dll", CharSet = CharSet.Unicode ) ]
        public static extern IntPtr FindWindowEx(
            IntPtr hwndParent,
            IntPtr hwndChildAfter,
            string lpszClass,
            string lpszWindow);

        [ DllImport( "User32.dll" ) ]
        public static extern IntPtr GetWindow
        (
            IntPtr hWnd,
            GW     uCmd
        );

        [ DllImport( "User32.dll" ) ]
        public static extern Int32 GetWindowTextLength
        (
            IntPtr hWnd
        );

        [ DllImport( "User32.dll", SetLastError = true, CharSet = CharSet.Auto ) ]
        public static extern Int32 GetWindowText
        (
            IntPtr hWnd,
            out StringBuilder lpString,
            Int32 nMaxCount
        );

        [ DllImport( "User32.dll", CharSet = CharSet.Auto ) ]
        public static extern Int32 GetClassName
        (
            IntPtr hWnd,
            out StringBuilder lpClassName,
            Int32 nMaxCount
        );

//      [ DllImport( "user32.dll", EntryPoint = "GetClassLongPtrW" ) ]
        [ DllImport( "user32.dll" ) ]
        public static extern UInt32 GetClassLong
        (
            IntPtr hWnd,
            int nIndex
        );

        [DllImport("user32.dll")]
        public static extern uint SetClassLong
        (
            IntPtr hWnd,
            int nIndex,
            uint dwNewLong
        );

        [ DllImport( "User32.dll", CharSet=CharSet.Auto ) ]
        public static extern UInt32 GetWindowThreadProcessId
        (
            IntPtr hWnd,
//          [ MarshalAs( UnmanagedType.
            out UInt32 lpdwProcessId
        );


        // Systray icons
        //[DllImport("user32.dll", SetLastError = true)]
       // public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpClassName, string lpWindowName);

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





    }
}

我检查了 32 位的应用程序,发现dwData != 0。 这帮助我了解问题出在 64 位上。

我更换了public UInt32 dwData; with public UInt64 dwData;.

    [ StructLayout( LayoutKind.Sequential ) ]
    internal struct TBBUTTON 
    {
        public Int32 iBitmap;
        public Int32 idCommand;
        public byte fsState;
        public byte fsStyle;
//      [ MarshalAs( UnmanagedType.ByValArray, SizeConst=2 ) ]
//      public byte[] bReserved;
        public byte bReserved1;
        public byte bReserved2;
       // public UInt32 dwData;
        public UInt64 dwData;
        public IntPtr iString;
    };  

The dwData现在大于零。
我成功获取与进程关联的按钮的窗口句柄并获取进程 pid:

  // window handle
  fixed (byte* pLocalBuffer = localBuffer)
  {
   ...
   ipWindowHandle = new IntPtr(iWindowHandle);

   threadId = User32.GetWindowThreadProcessId(ipWindowHandle, out processId);
   data.setProcessPid(processId);
  }

And the final result:
enter image description here

此解决方案找不到与隐藏的系统托盘图标关联的进程,这是我需要探索的新问题:)。

新的参考资料帮助我找到了这个解决方案的想法:
http://www.codeproject.com/Articles/10807/Shell-Tray-Info-Arrange-your-system-tray-icons http://www.codeproject.com/Articles/10807/Shell-Tray-Info-Arrange-your-system-tray-icons

这是一个名为“mklencke”的人的评论,他给出了 64 位的代码:

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

BOOL IsWow64()
{
    static bool isset = false;
    static BOOL bIsWow64 = FALSE;

    if (isset) {
        return bIsWow64;
    }

    //IsWow64Process is not available on all supported versions of Windows.
    //Use GetModuleHandle to get a handle to the DLL that contains the function
    //and GetProcAddress to get a pointer to the function if available.

    LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

    if(NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
        {
            //TODO handle error?
            return FALSE;
        }
    }

    isset = true;
    return bIsWow64;
}

typedef struct _TBBUTTON64 {
    int iBitmap;
    int idCommand;
    BYTE fsState;
    BYTE fsStyle;
    BYTE bReserved[6];
    DWORD64 dwData;
    DWORD64 iString;
} TBBUTTON64, NEAR* PTBBUTTON64, *LPTBBUTTON64;
typedef const TBBUTTON64 *LPCTBBUTTON64;

bool EnumSystemTray() { 
    bool bFound = false;

    // find system tray window
    HWND trayWnd = FindWindow(_T("Shell_TrayWnd"), NULL);
    if (trayWnd) {
        trayWnd = FindWindowEx(trayWnd, NULL,_T("TrayNotifyWnd"), NULL);
        if (trayWnd) {
            trayWnd = FindWindowEx(trayWnd, NULL,_T("SysPager"), NULL);
            if (trayWnd) {              
                trayWnd = FindWindowEx(trayWnd, NULL,_T("ToolbarWindow32"), NULL);
                bFound = true;
            }
        }
    }

    ASSERT(bFound);

    DWORD dwTrayPid;
    GetWindowThreadProcessId(trayWnd, &dwTrayPid);

    int count = (int) SendMessage(trayWnd, TB_BUTTONCOUNT, 0, 0);

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTrayPid);
    if (!hProcess) {
        return true;
    }

    BOOL bIsWow64 = IsWow64();

    SIZE_T dwSize = bIsWow64 ? sizeof(TBBUTTON64) : sizeof(TBBUTTON);
    LPVOID lpData = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
    if (!lpData) {
        return true;
    }

    // Loop through all systray icons
    for (int i = 0; i < count; i++) {
        HWND hwnd32;

        SendMessage(trayWnd, TB_GETBUTTON, i, (LPARAM)lpData);
        if ( bIsWow64 ) {
            // Try to read memory from 64-bit Explorer process. Hope the address of the traybar data is below 4GB

            TBBUTTON64 tbb;
            if (!ReadProcessMemory(hProcess, lpData, (LPVOID)&tbb, sizeof(TBBUTTON64), NULL)) {
                continue;
            }

            DWORD64 hwnd;

            // First member of TRAYDATA structure is HWND, so we can just use the address of the struct to read the member
            if (!ReadProcessMemory(hProcess, (LPCVOID)tbb.dwData, (LPVOID)&hwnd, sizeof(DWORD64), NULL)) {
                continue;
            }

            // Hope this does not get truncated, but we shouldn't have that many windows
            hwnd32 = (HWND)hwnd;
        } else {
            TBBUTTON tbb;
            if (!ReadProcessMemory(hProcess, lpData, (LPVOID)&tbb, sizeof(TBBUTTON), NULL)) {
                continue;
            }

            DWORD32 hwnd;

            // First member of TRAYDATA structure is HWND, so we can just use the address of the struct to read the member
            if (!ReadProcessMemory(hProcess, (LPCVOID)tbb.dwData, (LPVOID)&hwnd, sizeof(DWORD32), NULL)) {
                continue;
            }

            hwnd32 = (HWND)hwnd;
        }

        DWORD dwProcessId = 0;
        GetWindowThreadProcessId(hwnd32, &dwProcessId);

        // XXX - DO SOMETHING WITH dwProcessId
    }

    VirtualFreeEx(hProcess, lpData, NULL, MEM_RELEASE);

    return true;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何获取具有系统托盘图标的进程 的相关文章

随机推荐

  • Perl 中的“$x->Put”有什么作用?

    我正在看这段代码 diag cmd pack CCSV DIAG SUBSYS CMD F DIAG SUBSYS PWRDB PWRDB DIAG PKT SCRIPT processor select length s part s p
  • 为什么Datareader无法初始化?

    我们在类名之前使用abstract关键字来限制创建类的实例 但 datareader 不是一个抽象类 但我们无法创建它的实例 你能解释一下为什么吗 我搜索了它 然后发现它没有构造函数 这就是为什么我们无法创建对象 但据我所知 如果没有构造函
  • ActiveX初始化:AxHost.State对象

    我正在尝试使用 WinFormsHost Control 将 Unity3D ActiveX 控件嵌入到 WPF Form 中 实际上 在VS的属性窗口中设置路径时效果很好 但在我的代码文件中设置时它不会加载任何内容 这是控件的一个已知问题
  • VSCode 中的 .ejs 格式

    这是我的问题 它不可读 为了使 ejs 正常工作 我到目前为止添加了以下内容 我还有保存格式和更漂亮的格式 我正在寻找更好的格式的建议 以便我可以阅读它 files associations ejs html css postcss emm
  • 如何将 PreMake/CMake 集成到 C++ 构建工作流程中

    我目前正在研究 PreMake CMake 但是 我不明白如何在整个跨平台构建工作流程中使用它 事实上 它生成 makefile 或解决方案 那么 如何在每个目标平台上实际构建这些解决方案 您是否必须为每个目标维护一个构建脚本 例如 sh
  • 如何检查当前日期是否在java中两个重复出现的日期之间? [复制]

    这个问题在这里已经有答案了 我正在尝试创建一个应用程序 但在计算今天是否在学年中陷入困境 用户输入两个日期 没有年份 每年都会重复发生 这些是学年的开始和结束日期 我想检查当前日期是否在这两个日期之间 即使它重叠两年 因此 如果学校从 11
  • 推送通知到达时应用程序徽章图标未更新

    我看过关于的问题在午夜更新应用程序徽章 并提供以下选项 应用程序未启动或在后台 徽章数量可能会减少 https stackoverflow com questions 4846787 updating application badge a
  • 用户登录后访问登录页面如何重定向到首页?

    这是我的春季安全配置
  • 将事件函数绑定到类,但使用removeEventListener并删除引用,从而使垃圾收集器能够正常工作

    众所周知 当我们在 JavaScript 中创建类时 普通函数会返回类对象 但事件会返回事件对象 并且类对象会丢失 function class a this name a document addEventListener click t
  • 如何在 bash 中编写看门狗守护进程?

    我想要一种在 shell 脚本中编写守护进程的方法 该守护进程循环运行另一个应用程序 如果它死了则重新启动它 运行时使用 myscript sh从 SSH 会话中 它将启动守护程序的新实例 除非守护程序已在运行 当 SSH 会话结束时 守护
  • Shared_ptr 的隐式转换

    我有 U 类和 T 类的两个共享指针 其中 T 是 U 的基数 进行隐式转换是没有问题的shared ptr u to shared ptr u
  • 如何在 Jetpack Compose 中从 URL 加载图像? [复制]

    这个问题在这里已经有答案了 嗯 我正在研究 Compose UI 而且我只专注于基本的事情 其中之一是使用 Glide 显示来自 URL 的图像 我已尝试以下代码 但未调用委托 onResourceReady 和 onLoadCleared
  • 访问 servlet 实例

    虽然我真的无法想到这种情况的实际用例 但我纯粹希望这是一个好奇心驱动的问题 我知道 servlet 容器保存着 servlet 创建的所有实例 并将请求线程委托给这些实例 对这些实例进行管理也是有意义的 以避免在容器权限之外进行无根据的调用
  • 有没有办法在线程创建/销毁时调用库线程本地初始化/清理?

    这个问题类似于如何在线程创建和退出时调用函数 https stackoverflow com questions 42229612 how to call a function on a threads creation and exit但
  • iPhone 版本的“显示包内容”显示空白 PNG?

    所以我成功地完成了我的第一个 iPhone 版本构建 当我好奇地转到新鲜出炉的 app 文件的 显示包内容 时 我注意到所有包含的 PNG 都是空白的 它们都设置为适当的分辨率 但是当我打开它们时 除了默认的 Preview app 灰色之
  • 如何在 Ruby 中找到字符串的第一个非重复字母?

    我有一根绳子 teststring 我想在 Ruby 中找到第一个非重复字符 我有这个Python代码 def first non repeat character teststring unique repeated for charac
  • Flask-登录不重定向到上一页

    我看到了很多与此相关的问题 但无法解决我的问题 我有一个 Flask 应用程序 带有 Flask login 用于会话管理 而且 当我尝试在不登录的情况下查看页面时 我会被重定向到以下形式的链接 login next 2Fsettings
  • 手动将元素添加到 d3 中的选择中

    我正在尝试以编程方式在 d3 中创建一个表 其顶部有四分之一 左侧有值 给定一个四分之一向量 q1 q2 q3 q4 我想要表格 q1 q2 q3 q4 v1 v2 运行下面的代码时我得到的是 q2 q3 q4 v1 v2 请注意 第一列缺
  • DriveApp.GetFoldersByName() 始终返回 true

    我一直在玩谷歌驱动器脚本 我需要从电子表格创建一个文件夹 以防具有该名称的文件夹不存在 但问题是 它说该文件夹存在 即使它不存在 支票位于try功能 像这样 try currentName is the name of the folder
  • 如何获取具有系统托盘图标的进程

    我正在尝试创建获取具有系统托盘图标的进程列表的应用程序 我进行了大量搜索并找到了一些参考资料 http www raymond cc blog find out what program are running at windows sys