如何获取具有systray图标的进程

我正在尝试创建应用程序,以获取具有systray图标的进程列表。
我搜索了很多,发现了一些参考文献:

  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. 哪个Windows进程显示给定的任务栏系统托盘图标?

  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-托盘?论坛= csharpgeneral

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

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

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

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

我想要有systray图标的进程列表:
在此处输入图像描述 应用程序示例称为“AnVir任务管理器”

使用链接6中的代码,我成功遍历系统托盘按钮并查看每个按钮的文本:
在此处输入图像描述

但我不知道如何找到与每个trayicon有关的过程。

在代码项目中,他提到可以帮助识别进程的信息是dwData但问题是当我发现Systray中出现的按钮时,其dwData = 0
在此处输入图像描述

码:

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 tbButtons2 = new List(); 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现在大于零。
我成功获取与进程关联的按钮的窗口句柄并获取进程pid:

  // window handle fixed (byte* pLocalBuffer = localBuffer) { ... ipWindowHandle = new IntPtr(iWindowHandle); threadId = User32.GetWindowThreadProcessId(ipWindowHandle, out processId); data.setProcessPid(processId); } 

最后的结果是:
在此处输入图像描述

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

新的推荐帮助我找到了这个解决方案的想法:
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; }