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