我正在尝试创建获取具有systray图标的进程列表的应用程序。
我搜索了很多,发现了一些引用文献:
它们都是很好的资源,但对我来说最有用的是3和4。
在1中,有一个我想要的示例。
我想要具有systray图标的进程列表:
名为“AnVir任务管理器”的应用程序示例
使用链接6中的代码,我成功地遍历了系统托盘按钮,并看到了每个按钮的文本:
但是我不确定如何找到与每个纸盘图标相关的过程。
他在代码项目中提到可以帮助识别过程的信息是
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<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);
}
}
最佳答案
我在32bit上检查了应用程序,然后看到了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);
}
最终结果:
该解决方案找不到与隐藏的系统任务栏图标相关联的进程,这是我需要研究的新问题:)。
新的引用资料帮助我找到了该解决方案的主意:
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;
}
关于c# - 如何获取具有系统托盘图标的进程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33652756/