Você pode enviar um sinal ao Windows Explorer para atualizar os ícones da bandeja do sistema?

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

Pergunta

Esse problema vem me afetando há um bom tempo e tem sido muito chato.

Cada vez que faço login após uma reinicialização/desligamento, o explorador leva algum tempo para aparecer.Aguardei a inicialização de todos os serviços e então fiz o login, mas isso não faz nenhuma diferença.O resultado é sempre o mesmo:Alguns dos ícones não aparecem mesmo que os aplicativos tenham sido iniciados.

Pesquisei um pouco o código que faz com que um aplicativo "cole" um ícone nele, mas existe uma chamada de API que pode ser executada para que o Explorer relê todas as informações do ícone?Como invalidar ou redesenhar ou algo do tipo?


Aparentemente, parece que Jon estava certo e não é possível fazer isso.

Eu segui o código de Bob Dizzle e Mark Ransom e construí este (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;

Mas sem sucesso.

Eu até tentei com

InvalidateRect()
e ainda não apareceu.

Alguma outra sugestão?

Foi útil?

Solução

Dê uma olhada nesta entrada do blog: ATUALIZANDO A ÁREA DE NOTIFICAÇÃO DA BARRA DE TAREFAS.Estou usando este código para atualizar a bandeja do sistema e me livrar dos ícones órfãos e funciona perfeitamente.A entrada do blog é muito informativa e dá uma ótima explicação das etapas que o autor executou para descobrir sua solução.

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

Outras dicas

Dois detalhes importantes para quem usa a resposta de Louis (de ATUALIZANDO A ÁREA DE NOTIFICAÇÃO DA BARRA DE TAREFAS) no Windows 7 ou Windows 8:

Primeiro, como a resposta foi refletida, a janela intitulada "Área de Notificação" no XP agora é intitulada "Área de Notificação Promovida pelo Usuário" no Windows 7 (provavelmente no Vista) e superior.

Em segundo lugar, este código não limpa os ícones que estão atualmente ocultos.Eles estão contidos em uma janela separada.Use o código original para atualizar ícones visíveis e o seguinte para atualizar ícones 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 quem precisa apenas de um utilitário para fazer isso, em vez de código, criei um exe simples com esta atualização: Atualizar área de notificação

Inclua o seguinte código com o seu para atualizar a bandeja do 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);

Pelo que eu sei isso não é possível Gustavo - cabe a cada aplicação colocar seu ícone de notificação na bandeja do sistema e garantir que ele seja mantido no estado correto.

Você notará, às vezes, quando o explorer.exe trava, que certos ícones não reaparecem - isso não ocorre porque o processo travou, simplesmente porque o aplicativo não colocou o ícone de notificação na bandeja do sistema quando a nova instância do explorer.exe foi iniciada acima.Mais uma vez, é o aplicativo o responsável.

Desculpe não ter notícias melhores para você!

Abordei esse assunto no ano passado em meu Viciado em código weblog em um artigo intitulado [Delphi] Atualizando o SysTray.

Minha solução é uma DLL Delphi ActiveX/COM.O link de download ainda funciona (embora por quanto tempo eu não saiba se meu PLUGUE a adesão expirou.)

Eu uso o seguinte código C++ para colocar o identificador da janela na janela da bandeja. Observação: isso só foi testado no 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, e qualquer outra pessoa que queira fazer isso em C, com este código verificado compilado em um mingw recente (mais recente) no Windows 10 de 64 bits (mas com o pacote mingw de 32 bits instalado), isso parece funcionar no Windows XP / 2003 para se livrar dos ícones obsoletos da área de notificação.

Instalei o mingw via Chocolatey, assim:

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

(sua milhagem pode variar, no meu sistema, o compilador foi instalado aqui:

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

e então um simples

gcc refresh_notification_area.c

gerou um a.exe que resolveu um problema de ícone de área de notificação obsoleto que eu estava tendo no Windows 2003 (32 bits).

O código, adaptado de @Stephen Klancher acima, é (observe que isso só pode funcionar no Windows XP/2003, que atendeu aos meus 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;

}

Depois de muitas tentativas, descobri que há três questões que você deve saber:

  • O pai da janela da bandeja oculta é NotifyIconOverflowWindow, outro que não seja Shell_TrayWnd.
  • Você não deveria usar caption parâmetro de FindWindowEx para encontrar uma janela, porque essas são muitas versões do sistema operacional Windows, nem sempre são o mesmo título, obviamente.
  • Usar spy++ do Visual Studio para encontrar ou garantir o que você deseja.

Então, mudei o código de @Stephen Klancher e @Louis Davis, obrigado pessoal.

O código a seguir funcionou para mim.

#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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top