14

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

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

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


显然,看起来 Jon 是对的,而且不可能做到。

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

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()
仍然没有出现。

还有其他建议吗?

4

8 回答 8

13

看看这个博客条目:刷新任务栏通知区域。我正在使用此代码刷新系统托盘以摆脱孤立的图标,并且它运行良好。该博客条目提供了非常丰富的信息,并很好地解释了作者为发现他的解决方案而执行的步骤。

#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);
}
于 2009-06-27T14:33:02.797 回答
13

在 Windows 7 或 Windows 8 上使用 Louis 的答案(来自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:刷新通知区域

于 2013-08-03T23:54:23.437 回答
4

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

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);
于 2008-09-16T17:24:19.463 回答
2

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

当 explorer.exe 崩溃时,您有时会注意到某些图标不会重新出现 - 这不是因为他们的进程已经崩溃,只是因为他们的应用程序在 explorer.exe 的新实例启动时没有将 notifyicon 放入系统托盘向上。再次,它是负责的应用程序。

很抱歉没有更好的消息告诉你!

于 2008-09-16T17:23:11.527 回答
2

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

我的解决方案是 Delphi ActiveX/COM DLL。下载链接仍然有效(尽管我不知道我的PLUG会员资格已经失效了多久。)

于 2009-06-27T14:45:29.310 回答
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");
}

于 2008-09-16T17:35:23.307 回答
1

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

  • 隐藏托盘窗口的父级NotifyIconOverflowWindow不是Shell_TrayWnd.
  • 您不应该使用caption参数 ofFindWindowEx来查找窗口,因为这些是许多语言版本的 Windows 操作系统,它们显然并不总是相同的标题。
  • 使用spy++Visual Studio 查找或确认您想要的内容。

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

以下代码对我有用。

#define FW(x,y) FindWindowEx(x, NULL, y, L"")
void RefreshTaskbarNotificationArea()
{
    HWND hNotificationArea;
    RECT r;
    GetClientRect(hNotificationArea = FindWindowEx(FW(NULL, L"NotifyIconOverflowWindow"), NULL, L"ToolbarWindow32", NULL), &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);
        }
    }
}
于 2019-05-11T09:02:51.947 回答
0

@Skip R,以及其他任何想在 C 中执行此操作的人,并在 Windows 10 64 位(但安装了 mingw 32 位软件包)上的最近(最新)mingw 中验证了此代码,这似乎适用于 Windows XP /2003 摆脱陈旧的通知区域图标。

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

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

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

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

然后一个简单的

gcc refresh_notification_area.c

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

改编自上面@Stephen Klancher 的代码是(请注意,这可能仅适用于Windows XP/2003,它实现了我的目的):

#include <windows.h>

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

int main ()
{

    HWND hNotificationArea;
    RECT r;

    //WinXP
    // technique found at:
    // https://stackoverflow.com/questions/74723/can-you-send-a-signal-to-windows-explorer-to-make-it-refresh-the-systray-icons#18038441
    GetClientRect(
        hNotificationArea = FindWindowEx(
            FW(FW(FW(NULL, "Shell_TrayWnd"), "TrayNotifyWnd"), "SysPager"),
            NULL,
            "ToolbarWindow32",
            "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);

  return 0;

}
于 2018-12-27T00:18:48.067 回答