Você pode enviar um sinal ao Windows Explorer para atualizar os ícones da bandeja do sistema?
-
09-06-2019 - |
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?
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 sejaShell_TrayWnd
. - Você não deveria usar
caption
parâmetro deFindWindowEx
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);
}
}
}