问题
I am trying to get the hwnd of the current tray icons. what I did is getting the hWnd of system trat window by using this code:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
static IntPtr GetSystemTrayHandle()
{
IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "TrayNotifyWnd", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "SysPager", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "ToolbarWindow32", null);
return hWndTray;
}
}
}
return IntPtr.Zero;
}
which I took from here: Finding which applications and services are listed in the System Tray?
and then I Enumrated the child windows of that hWnd by using this code:
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
list.Add(handle);
// You can modify this to check to see if you want to cancel the operation, then return a null here
return true;
}
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
which I took from here:enumchildwindows (user32)
then I used it like this:
IntPtr temp = GetSystemTrayHandle();
List<IntPtr> tst = GetChildWindows(temp);
MessageBox.Show(tst.Count.ToString());
foreach (IntPtr ip in tst)
{
MessageBox.Show(ip.ToString());
}
but the List<IntPtr> tst
is empty.. any idea why? am I doing this wrong?
回答1:
The 'children' of the ToolbarWindow32 are not windows. They are toolbar buttons. You'd use the TB_BUTTONCOUNT message to retrieve the number of buttons, TB_GETBUTTONINFO message to retrieve info about such a button. Quite hard to do btw since the window belongs to another process, just using SendMessage() doesn't work because the pointer isn't valid. And ultimately futile, such a button doesn't contain any information about what kind of process is associated with the icon. That's info that's buried inside the shell, you can't get to it.
回答2:
There are no child handles. You can verify this via Spy++.
It is not hosing sub-controls, but rendering and handling things like tooltips directly.
回答3:
I checked that if window is opened on desktop then it has styles:
WS_VISIBLE=true
WS_MINIMIZE=false
if window is in taskbar:
WS_VISIBLE=true
WS_MINIMIZE=true
if window is in system tray:
WS_VISIBLE=false
WS_MINIMIZE=true
So you can play with styles to determine if window is in tray:
public IsWindowFromTray(hWnd)
{
bool isMinimized = Win32Natives.IsIconic(hWnd);
bool isVisible = Win32Natives.IsWindowVisible(hWnd);
return isMinimized && !isVisible;
}
For the majority of apps it works.
PS: I used pinvoke
[DllImport("user32.dll")]
public static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);
来源:https://stackoverflow.com/questions/5174120/c-sharp-how-to-determine-if-hwnd-is-in-tray-icons