您可以向Windows资源管理器发送信号以刷新系统托盘图标吗?

时间:2008-09-16 17:19:00

标签: icons windows-explorer system-tray systray

这个问题困扰了我很长一段时间,而且真的很烦人。

每次重启/重启后登录时,资源管理器都需要一些时间才能显示。 我已经采取了等待所有服务启动然后我登录的步骤,但它没有任何区别。 结果始终相同:即使应用程序已启动,某些图标也不会显示。

我已经挖了一些代码,让一个应用程序“粘贴”在那里的图标,但是有一个API调用可以执行,所以资源管理器重新读取所有图标信息?像无效或重绘或类似的东西?


显然,看起来乔恩是对的,这是不可能做到的。

我遵循了Bob Dizzle和Mark Ransom代码并构建了这个(Delphi Code):

procedure Refresh;
var
  hSysTray: THandle;
begin
  hSysTray := GetSystrayHandle;
  SendMessage(hSysTray, WM_PAINT, 0, 0);
end;

function GetSystrayHandle: THandle;
var
  hTray, hNotify, hSysPager: THandle;
begin
  hTray := FindWindow('Shell_TrayWnd', '');
  if hTray = 0 then
  begin
    Result := hTray;
    exit;
  end;

  hNotify := FindWindowEx(hTray, 0, 'TrayNotifyWnd', '');
  if hNotify = 0 then
  begin
    Result := hNotify;
    exit;
  end;

  hSyspager := FindWindowEx(hNotify, 0, 'SysPager', '');
  if hSyspager = 0 then
  begin
    Result := hSyspager;
    exit;
  end;

  Result := FindWindowEx(hSysPager, 0, 'ToolbarWindow32', 'Notification Area');
end;

但无济于事。

我甚至尝试过使用

InvalidateRect()
但仍然没有显示。

还有其他建议吗?

8 个答案:

答案 0 :(得分:10)

查看此博客文章:REFRESHING THE TASKBAR NOTIFICATION AREA。我正在使用此代码刷新系统托盘以摆脱孤立的图标,它的工作完美。 博客文章内容非常丰富,并对作者为发现他的解决方案所采取的步骤提供了很好的解释。

#define FW(x,y) FindWindowEx(x, NULL, y, L"")

void RefreshTaskbarNotificationArea()
{
    HWND hNotificationArea;
    RECT r;

    GetClientRect(
        hNotificationArea = FindWindowEx(
            FW(FW(FW(NULL, L"Shell_TrayWnd"), L"TrayNotifyWnd"), L"SysPager"),
            NULL,
            L"ToolbarWindow32",
            // L"Notification Area"), // Windows XP
            L"User Promoted Notification Area"), // Windows 7 and up
        &r);

    for (LONG x = 0; x < r.right; x += 5)
        for (LONG y = 0; y < r.bottom; y += 5)
            SendMessage(
                hNotificationArea,
                WM_MOUSEMOVE,
                0,
                (y << 16) + x);
}

答案 1 :(得分:10)

在Windows 7或Windows 8上使用路易斯答案(来自REFRESHING THE TASKBAR NOTIFICATION AREA)的任何人的两个重要细节:

首先,正如答案反映出来的那样,XP中标题为“通知区域”的窗口现在在Windows 7中标题为“用户升级通知区域”(实际上可能是Vista)及以上。

其次,此代码不会清除当前隐藏的图标。这些包含在一个单独的窗口中。使用原始代码刷新可见图标,使用以下内容刷新隐藏图标。

//Hidden icons
GetClientRect(
    hNotificationArea = FindWindowEx(
        FW(NULL, L"NotifyIconOverflowWindow"),
        NULL,
        L"ToolbarWindow32",
        L"Overflow Notification Area"),
    &r);

for (LONG x = 0; x < r.right; x += 5)
    for (LONG y = 0; y < r.bottom; y += 5)
        SendMessage(
            hNotificationArea,
            WM_MOUSEMOVE,
            0,
            (y << 16) + x);

对于只需要运行实用程序而不是代码的任何人,我使用此更新构建了一个简单的exe:Refresh Notification Area

答案 2 :(得分:3)

包含以下代码以刷新系统托盘。

public const int WM_PAINT = 0xF;
[DllImport("USER32.DLL")]
public static extern int SendMessage(IntPtr hwnd, int msg, int character,
                                     IntPtr lpsText);

Send WM_PAINT Message to paint System Tray which will refresh it.
SendMessage(traynotifywnd, WM_PAINT, 0, IntPtr.Zero);

答案 3 :(得分:2)

据我所知,Gustavo是不可能的 - 每个应用程序都要将其notifyicon放在系统托盘中,并确保它保持在正确的状态。

有时当explorer.exe崩溃某些图标不再出现时你会注意到 - 这不是因为他们的进程已崩溃,只是因为他们的应用程序在探测器的新实例时没有将notifyicon放入系统托盘中.exe启动了。再一次,这是应用程序的责任。

抱歉不要为你提供更好的消息!

答案 4 :(得分:2)

我去年在我的Codeaholic博客上发表了一篇题为[Delphi] Updating SysTray的文章,讨论了这个问题。

我的解决方案是Delphi ActiveX / COM DLL。下载链接仍然有效(但由于我的PLUG会员资格已失效,我还不知道多长时间。)

答案 5 :(得分:1)

我使用以下C ++代码获取托盘窗口的窗口句柄。 注意:仅在Windows XP上测试过。

HWND FindSystemTrayIcons(void)
{
    // the system tray icons are contained in a specific window hierarchy;
    // use the Spy++ utility to see the chain
    HWND hwndTray = ::FindWindow("Shell_TrayWnd", "");
    if (hwndTray == NULL)
        return NULL;
    HWND hwndNotifyWnd = ::FindWindowEx(hwndTray, NULL, "TrayNotifyWnd", "");
    if (hwndNotifyWnd == NULL)
        return NULL;
    HWND hwndSysPager = ::FindWindowEx(hwndNotifyWnd, NULL, "SysPager", "");
    if (hwndSysPager == NULL)
        return NULL;
    return ::FindWindowEx(hwndSysPager, NULL, "ToolbarWindow32", "Notification Area");
}

答案 6 :(得分:0)

@Skip R,以及其他想要用C进行此操作的人,并在Windows 10 64位(但安装了mingw 32位程序包)上使用最新(最新)的mingw编译了此代码,并进行了验证Windows XP / 2003中删除旧的通知区域图标。

我通过Chocolatey安装了mingw,如下所示:

.toast

(您的里程可能会有所不同,在我的系统上,然后将编译器安装在此处:

choco install mingw --x86 --force --params "/exception:sjlj"

然后是一个简单的

C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw32\bin\gcc.exe

生成了a.exe,该文件解决了我在Windows 2003(32位)上遇到的过时通知区域图标问题。

从上面的@Stephen Klancher改编而成的代码是(请注意,此代码只能在满足我目的的Windows XP / 2003上运行):

gcc refresh_notification_area.c

答案 7 :(得分:0)

经过多次尝试,我发现您必须了解三个问题:

  • 隐藏托盘窗口的父级是Unable to find x,而不是NotifyIconOverflowWindow
  • 您不应该使用Shell_TrayWnd的{​​{1}}参数来查找窗口,因为这些是Windows OS的许多语言版本,显然它们并不总是相同的标题。
  • 使用Visual Studio的caption查找或确保您想要的内容。

所以,我更改了@Stephen Klancher和@Louis Davis的代码,谢谢。

以下代码对我有用。

FindWindowEx