C# 以编程方式刷新系统托盘图标

C# 以编程方式刷新系统托盘图标,c#,pinvoke,system-tray,trayicon,C#,Pinvoke,System Tray,Trayicon,我有一个应用程序,它有一个系统托盘图标。卸载时,如果进程正在运行,我将终止该进程。因此,由于我没有优雅地停止该应用程序,该图标仍保留在系统托盘中,只有当我们将鼠标悬停在其上时才会删除。我编写了一个代码,可以沿着托盘运行光标,并将光标恢复到初始位置。这就是我所做的: [DllImport("user32.dll")] static extern IntPtr FindWindow(string className, string windowName);

我有一个应用程序,它有一个系统托盘图标。卸载时,如果进程正在运行,我将终止该进程。因此,由于我没有优雅地停止该应用程序,该图标仍保留在系统托盘中,只有当我们将鼠标悬停在其上时才会删除。我编写了一个代码,可以沿着托盘运行光标,并将光标恢复到初始位置。这就是我所做的:

        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string className, string windowName);
        [DllImport("user32.dll")]
        static extern IntPtr FindWindowEx(IntPtr parent, IntPtr child, string className, string windowName);
        [DllImport("user32.dll")]
        static extern bool GetWindowRect(HandleRef handle, out RECT rct);

        [StructLayout(LayoutKind.Sequential)]
        struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        void RefreshTray()
        {
            IntPtr taskbar_Handle = FindWindow("Shell_Traywnd", "");
            IntPtr tray_Handle = FindWindowEx(taskbar_Handle, IntPtr.Zero, "TrayNotifyWnd", "");

            RECT rct;

            if (!(GetWindowRect(new HandleRef(null, tray_Handle), out rct)))
            {
            }

            System.Drawing.Point init = Control.MousePosition;

            for (int i = rct.Left; i < rct.Right-20; i++)
            {
                Cursor.Position = new System.Drawing.Point(i, (rct.Bottom + rct.Top) / 2);
            }

            Cursor.Position = init;
         }
[DllImport(“user32.dll”)]
静态外部IntPtr FindWindow(字符串类名称、字符串窗口名称);
[DllImport(“user32.dll”)]
静态外部IntPtr FindWindowEx(IntPtr父级、IntPtr子级、字符串类名称、字符串窗口名称);
[DllImport(“user32.dll”)]
静态外部bool GetWindowRect(HandleRef handle,out RECT rct);
[StructLayout(LayoutKind.Sequential)]
结构矩形
{
公共int左;
公共int Top;
公共权利;
公共int底部;
}
空刷新托盘()
{
IntPtr taskbar_Handle=FindWindow(“Shell_Traywnd”);
IntPtr-tray_-Handle=FindWindowEx(任务栏_-Handle,IntPtr.Zero,“TrayNotifyWnd”和“”);
RECT-rct;
if(!(GetWindowRect(新句柄ref(null,托盘句柄),out rct)))
{
}
System.Drawing.Point init=Control.MousePosition;
for(int i=rct.Left;i
除启用“不显示通知图标”选项外,这在所有情况下都很有效。在这种情况下,有什么方法可以刷新托盘吗

编辑
正如评论所暗示的,我改变了我的方法。我没有终止托盘应用程序,而是在我的应用程序服务(是的,忘了提到,我有一个服务也在应用程序中运行)和托盘应用程序之间建立了通信。卸载时,我会停止服务,通过服务停止方法,我会向托盘应用程序发送特定格式的套接字消息,并要求其关闭,我会将通知图标可见性设置为false。这将使托盘应用程序在后台运行,因此我使用“taskkill”删除该应用程序。它在Win7和Vista中运行良好,但在WinXP中无法正常工作。但我还没有编写任何特定于环境的代码。有任何可能的线索吗?

如果您不想这样做并且没有运行.NET4.0,那么使用管道或TCP之类的东西关闭当前实例应该不难

正如大家所暗示的,问题在于,通过终止进程,它没有机会注销其托盘图标实例,因此它会一直存在,直到Windows尝试向其发送事件(下次在其上移动鼠标时),Windows才会将其删除

根据您使用的安装程序的不同,这可能非常简单,也可能更加困难。大多数流行的安装程序框架都支持插件,其中一些支持管道,更多的支持TCP请求。或者,编写一个小的可执行文件,安装程序可以在卸载过程开始之前运行,该文件与主应用程序通信并发送关闭消息


最后,如果您可以使用.NET4.0,那么我建议您查看内置的System.IO.Pipes命名空间和包含的类。

这与我使用的类似。 一个简单的浮动键盘我添加到一个触摸画廊界面。用户还希望将我的键盘作为一个独立的应用程序放在桌面上。所以我做了这个,为它创建了一个托盘应用程序。现在-如果它打开了,他们启动了我的图库怎么办

他们将有两个键盘

当然-用户可以结束第一个-但更容易结束它。我杀了它没有任何影响,所以我杀了它。但托盘图标仍然保留,因为它正在等待事件。为了解决这个问题,我刷新了托盘区域

请注意-这仅适用于英语区域设置安装。要使其在另一种语言上工作,请将“用户提升的通知区域”和“通知区域”更改为翻译的/等效的字符串

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}

[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
    string lpszWindow);

[DllImport("user32.dll")]
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

public static void RefreshTrayArea()
{
    IntPtr systemTrayContainerHandle = FindWindow("Shell_TrayWnd", null);
    IntPtr systemTrayHandle = FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
    IntPtr sysPagerHandle = FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
    IntPtr notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
    if (notificationAreaHandle == IntPtr.Zero)
    {
        notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32",
            "User Promoted Notification Area");
        IntPtr notifyIconOverflowWindowHandle = FindWindow("NotifyIconOverflowWindow", null);
        IntPtr overflowNotificationAreaHandle = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero,
            "ToolbarWindow32", "Overflow Notification Area");
        RefreshTrayArea(overflowNotificationAreaHandle);
    }
    RefreshTrayArea(notificationAreaHandle);
}

private static void RefreshTrayArea(IntPtr windowHandle)
{
    const uint wmMousemove = 0x0200;
    RECT rect;
    GetClientRect(windowHandle, out rect);
    for (var x = 0; x < rect.right; x += 5)
        for (var y = 0; y < rect.bottom; y += 5)
            SendMessage(windowHandle, wmMousemove, 0, (y << 16) + x);
}
[StructLayout(LayoutKind.Sequential)]
公共结构矩形
{
公共int左;
公共int top;
公共权利;
公共int底部;
}
[DllImport(“user32.dll”)]
公共静态外部IntPtr FindWindow(字符串lpClassName,字符串lpWindowName);
[DllImport(“user32.dll”)]
公共静态外部IntPtr FindWindowEx(IntPtr hwndParent、IntPtr hwndChildAfter、字符串lpszClass、,
字符串(窗口);
[DllImport(“user32.dll”)]
公共静态外部bool GetClientRect(IntPtr hWnd、out RECT lpRect);
[DllImport(“user32.dll”)]
公共静态外部IntPtr SendMessage(IntPtr hWnd、uint msg、int wParam、int lParam);
公共静态无效刷新Trayarea()
{
IntPtr systemTrayContainerHandle=FindWindow(“Shell\u TrayWnd”,null);
IntPtr systemTrayHandle=FindWindowEx(systemTrayContainerHandle,IntPtr.Zero,“TrayNotifyWnd”,null);
IntPtr sysPagerHandle=FindWindowEx(systemTrayHandle,IntPtr.Zero,“SysPager”,null);
IntPtr notificationAreaHandle=FindWindowEx(sysPagerHandle,IntPtr.Zero,“工具栏窗口32”,“通知区域”);
if(notificationAreaHandle==IntPtr.Zero)
{
notificationAreaHandle=FindWindowEx(sysPagerHandle,IntPtr.Zero,“ToolbarWindow32”,
“用户升级通知区”);
IntPtr notifyIconOverflowWindowHandle=FindWindow(“NotifyIconOverflowWindow”,null);
IntPtr overflownotificationeahandle=FindWindowEx(notifyIconOverflowWindowHandle,IntPtr.Zero,
“工具栏窗口32”、“溢出通知区”);
RefreshTrayArea(overflowNotificationAreaHandle);
}
RefreshTrayArea(通知区域句柄);
}
私有静态void refreshttrayarea(IntPtr windowHandle)
{
常数u