C# 如何判断hwnd是否在托盘图标中

发布于 2024-10-19 21:32:11 字数 2657 浏览 6 评论 0原文

我正在尝试获取当前托盘图标的 hwnd。 我所做的是使用以下代码获取系统trat窗口的hWnd:

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

我从这里获取的代码: 查找系统托盘中列出了哪些应用程序和服务?

然后我使用以下代码枚举了该 hWnd 的子窗口

[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);

:从这里开始:enumchildwindows (user32)

然后我像这样使用它:

IntPtr temp = GetSystemTrayHandle();
List<IntPtr> tst = GetChildWindows(temp);
MessageBox.Show(tst.Count.ToString());
foreach (IntPtr ip in tst)
{
    MessageBox.Show(ip.ToString());
}

但是 <代码>列表tst 是空的..知道为什么吗?我做错了吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葬シ愛 2024-10-26 21:32:11

ToolbarWindow32 的“子级”不是窗口。它们是工具栏按钮。您可以使用 TB_BUTTONCOUNT 消息来检索按钮的数量,使用 TB_GETBUTTONINFO 消息来检索有关此类按钮的信息。顺便说一句,由于窗口属于另一个进程,因此很难做到,仅使用 SendMessage() 不起作用,因为指针无效。最终是徒劳的,这样的按钮不包含任何有关与图标关联的进程类型的信息。这些信息隐藏在外壳内,您无法获取它。

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.

2024-10-26 21:32:11

没有子句柄。您可以通过 Spy++ 验证这一点。

它不是托管子控件,而是直接渲染和处理工具提示等内容。

在此处输入图像描述

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.

enter image description here

也只是曾经 2024-10-26 21:32:11

我查了一下
如果窗口在桌面上打开,则它具有样式:

WS_VISIBLE=true
WS_MINIMIZE=false

如果窗口在任务栏中:

WS_VISIBLE=true
WS_MINIMIZE=true

如果窗口在系统托盘中:

WS_VISIBLE=false
WS_MINIMIZE=true

因此您可以使用样式来确定窗口是否在托盘中:

public IsWindowFromTray(hWnd)
{    
    bool isMinimized = Win32Natives.IsIconic(hWnd);
    bool isVisible = Win32Natives.IsWindowVisible(hWnd);

    return isMinimized && !isVisible;
}

对于大多数应用程序来说,它都有效。

PS:我用的是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);

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文