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

标签 c# c++ winapi taskbar

我正在尝试创建应用程序来获取具有系统托盘图标的进程列表。
我搜索了很多,发现了很多引用文献:

  1. 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

  3. 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

  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-tray?forum=csharpgeneral

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

  7. Get ToolTip Text from Icon in System Tray

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

1我们有一个我想要的例子。

我想要有系统托盘图标的进程列表:
enter image description here 名为“AnVir 任务管理器”的应用程序示例

使用来自链接 6 的代码我成功地遍历了系统托盘按钮并查看了每个按钮的文本:
enter image description here

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

在代码项目中他提到可以帮助识别进程的信息是 dwData 但问题是当我发现出现在 Systray 中的按钮时,它的 dwData = 0:
enter image description here

代码:

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

Engine.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; 替换为 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;
    };  

dwData 现在大于零。
成功获取进程关联按钮的windows句柄,获取进程pid:

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

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

最终结果:
enter image description here

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

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

这是给出 64 位代码的名为“mklencke”的人的评论:

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

关于c# - 如何获取具有系统托盘图标的进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33652756/

相关文章:

c++ - WTSEnumerateSessions API获取的session ID是否唯一?

c# - 结构数组 - 数组元素是引用类型还是值类型?

c# - 使用 ClickOnce 部署更新本地 SQL Server 数据库

c# - CSharp 预准备语句与 MySQL 不起作用

c++无法转换参数

c++ - mingw 编译错误 : invalid conversion from 'FARPROC ' to 'void*' , 但 msvc 编译正常

c# - ASP.NET MVC 文件路径结果 : How to return an html file not found?

c++ - NSString 弱持有 std::string 的 const char *

c++ - 如何将 std::unordered_multimap<uint, T> 转储到 std::vector<T>?

c++ - 限制从计时器运行的线程数