Можете ли вы отправить сигнал проводнику Windows, чтобы он обновил значки на панели задач?

StackOverflow https://stackoverflow.com/questions/74723

Вопрос

Эта проблема беспокоит меня уже довольно давно и очень раздражает.

Каждый раз, когда я вхожу в систему после перезагрузки/выключения питания, проводнику требуется некоторое время, чтобы появиться.Я дождался загрузки всех служб, а затем вошел в систему, но это не имеет никакого значения.Результат всегда один и тот же:Некоторые значки не отображаются, даже если приложения запущены.

Я немного покопался в коде, который заставляет одно приложение «вставлять» туда значок, но есть ли вызов API, который можно выполнить, чтобы проводник перечитывал всю эту информацию о значке?Например, сделать недействительным, перерисовать или что-то в этом роде?


Судя по всему, Джон был прав и сделать это невозможно.

Я следовал коду Боба Диззла и Марка Рэнсома и создал это (код 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()
и до сих пор нет шоу.

Есть еще предложения?

Это было полезно?

Решение

Взгляните на эту запись в блоге: ОБНОВЛЕНИЕ ОБЛАСТИ УВЕДОМЛЕНИЙ ПАНЕЛИ ЗАДАЧ.Я использую этот код, чтобы обновить системный трей, чтобы избавиться от бесхозных значков, и он работает отлично.Запись в блоге очень информативна и дает подробное объяснение шагов, которые автор предпринял, чтобы найти свое решение.

#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);
}

Другие советы

Две важные детали для тех, кто использует ответ Луи (из ОБНОВЛЕНИЕ ОБЛАСТИ УВЕДОМЛЕНИЙ ПАНЕЛИ ЗАДАЧ) в Windows 7 или Windows 8:

Во-первых, как было показано в ответе, окно под названием «Область уведомлений» в 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-файл с этим обновлением: Обновить область уведомлений

Включите следующий код в свой, чтобы обновить системный трей.

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

Насколько я знаю, это невозможно, Густаво - каждое приложение должно поместить свой значок уведомления в системный трей и обеспечить его поддержание в правильном состоянии.

Иногда при сбое explorer.exe вы можете заметить, что некоторые значки не появляются снова — это не потому, что их процесс вышел из строя, просто их приложение не поместило значок уведомления на панель задач при запуске нового экземпляра explorer.exe. вверх.Опять же, виновато приложение.

Извините, что у меня нет для вас хороших новостей!

Я освещал эту тему в прошлом году в своем кодоголик блог в статье под названием [Delphi] Обновление SysTray.

Мое решение — это DLL Delphi ActiveX/COM.Ссылка для скачивания все еще работает (хотя как долго я не знаю, так как мой ЗАТЫКАТЬ членство истекло.)

Я использую следующий код 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");
}

@Skip R и все, кто хочет сделать это на C, с проверенным этим кодом, скомпилированным в последней (самой последней) версии mingw в 64-разрядной версии Windows 10 (но с установленным 32-разрядным пакетом mingw), похоже, это работает в Windows XP / 2003, чтобы избавиться от устаревших значков в области уведомлений.

Я установил mingw через Chocolatey, вот так:

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;

}

После многих попыток я обнаружил, что есть три проблемы, которые вам необходимо знать:

  • Родителем окна скрытого лотка является NotifyIconOverflowWindow, Кроме как Shell_TrayWnd.
  • Вы не должны использовать caption параметр FindWindowEx Чтобы найти окно, поскольку существует множество языковых версий ОС 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);
        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top