¿Puedes enviar una señal al Explorador de Windows para que actualice los íconos de la bandeja del sistema?

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

Pregunta

Este problema me aqueja desde hace bastante tiempo y ha sido realmente molesto.

Cada vez que inicio sesión después de reiniciar/encender, el explorador tarda un tiempo en aparecer.He dado el paso de esperar a que se inicien todos los servicios y luego inicio sesión, pero no hace ninguna diferencia.El resultado es siempre el mismo:Algunos de los íconos no aparecen incluso si las aplicaciones se han iniciado.

He investigado un poco el código que hace que una aplicación "pegue" un ícono allí, pero ¿hay alguna llamada API que se pueda realizar para que el explorador vuelva a leer toda la información del ícono?¿Como invalidar o volver a dibujar o algo por el estilo?


Al parecer, Jon tenía razón y no es posible hacerlo.

Seguí el código de Bob Dizzle y Mark Ransom y construí esto (Código 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;

Pero fue en vano.

Incluso lo he probado con

InvalidateRect()
y todavía no se presenta.

¿Cualquier otra sugerencia?

¿Fue útil?

Solución

Echa un vistazo a esta entrada de blog: ACTUALIZAR EL ÁREA DE NOTIFICACIÓN DE LA BARRA DE TAREAS.Estoy usando este código para actualizar la bandeja del sistema y deshacerme de los íconos huérfanos y funciona perfectamente.La entrada del blog es muy informativa y ofrece una excelente explicación de los pasos que siguió el autor para descubrir su solución.

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

Otros consejos

Dos detalles importantes para cualquiera que utilice la respuesta de Louis (de ACTUALIZAR EL ÁREA DE NOTIFICACIÓN DE LA BARRA DE TAREAS) en Windows 7 o Windows 8:

Primero, como se reflejó en la respuesta, la ventana titulada "Área de notificación" en XP ahora se titula "Área de notificación promocionada por el usuario" en Windows 7 (en realidad, probablemente Vista) y versiones posteriores.

En segundo lugar, este código no borra los iconos que están actualmente ocultos.Estos están contenidos en una ventana separada.Utilice el código original para actualizar los íconos visibles y el siguiente para actualizar los íconos ocultos.

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

Para cualquiera que solo necesite ejecutar una utilidad para lograr esto, en lugar de código, construí un archivo ejecutable simple con esta actualización: Actualizar área de notificación

Incluya el siguiente código con el suyo para actualizar la bandeja del sistema.

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

Hasta donde yo sé, eso no es posible, Gustavo: depende de cada aplicación colocar su ícono de notificación en la bandeja del sistema y asegurarse de que se mantenga en el estado correcto.

A veces, cuando explorer.exe falla, notará que ciertos íconos no reaparecen; esto no se debe a que su proceso haya fallado, simplemente a que su aplicación no colocó el ícono de notificación en la bandeja del sistema cuando se inició la nueva instancia de explorer.exe. arriba.Una vez más, es la aplicación la responsable.

¡Lamento no tener mejores noticias para ti!

Cubrí este tema el año pasado en mi Adicto al código blog en un artículo titulado [Delphi] Actualización de SysTray.

Mi solución es una DLL Delphi ActiveX/COM.El enlace de descarga todavía funciona (aunque no sé por cuánto tiempo más, ENCHUFAR la membresía ha caducado.)

Utilizo el siguiente código C++ para obtener el identificador de la ventana de la bandeja. Nota: esto sólo se ha probado en 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, y cualquiera que quiera hacer esto en C, con este código verificado compilado en un mingw reciente (más reciente) en Windows 10 de 64 bits (pero con el paquete mingw de 32 bits instalado), esto parece funcionar en Windows XP. / 2003 para deshacerse de los íconos obsoletos del área de notificación.

Instalé mingw a través de Chocolatey, así:

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

(Su kilometraje puede variar en eso, en mi sistema, el compilador se instaló aquí:

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

y luego un simple

gcc refresh_notification_area.c

produjo un archivo a.exe que resolvió un problema obsoleto con el ícono del área de notificación que estaba teniendo en Windows 2003 (32 bits).

El código, adaptado de @Stephen Klancher arriba es (tenga en cuenta que esto solo puede funcionar en Windows XP/2003, que cumplió mis propósitos):

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

}

Después de intentarlo muchas veces, descubrí que hay tres cuestiones que debes conocer:

  • El padre de la ventana de la bandeja oculta es NotifyIconOverflowWindow, aparte de Shell_TrayWnd.
  • No deberías usar caption parámetro de FindWindowEx para encontrar una ventana, debido a que hay muchas versiones de idiomas del sistema operativo Windows, no siempre tienen el mismo título, obviamente.
  • Usar spy++ de Visual Studio para encontrar o asegurar lo que desea.

Entonces, cambié el código de @Stephen Klancher y @Louis Davis, gracias a todos.

El siguiente código funcionó para mí.

#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);
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top