Si il y a bien un sujet qui m’obsède, dans mes développement, et depuis un moment, c’est bien celui là.
J’ai commencé à m’y intéressé lors d’un développement réalisé pour 1 client qui m’avait demandé l’écriture d’un outil permettant une interaction avec l’utilisateur au travers du SysTray.
Il s’est avéré que suite à l’utilisation d’un Object COM relativement ancien, j’ai eu besoin de tuer cette application dans certaines conditions via la commande:
TaskKill /F /IM monApplication
Cette commande a pour conséquence de tuer littéralement mon application. Mais avec un effet de bord assez gênant, son icone reste présent au niveau du SysTray.
D’autres applications très répandues subissent le même effet en cas de fermeture brutale (ex: Live Messenger, Outlook, …).
Comme je ne ferme pas mon application correctement, je n’ai donc pas, au niveau du code même, la possibilité de gérer cette événement inattendu.
Le fait de survoler le SysTray avec sa souris suffit à faire disparaitre les icones orphelins.
J’ai donc eu le besoin de rafraichir cette zone via la programmation.
A. API WIN32: User32.dll
Dans un premier temps, je me suis tourné vers les API Win32 de Windows pour trouver quelle fonction pouvait m’aider sur le sujet.
Au niveau de la Dll User32, il existe 3 fonctions qui semblaient très intéressantes:
- FindWindow : Fonction permettant de trouver le Handle de l’objet de type Shell_TrayWnd se trouvant au premier niveau de ma recherche
- FindWindowEx: Fonction permettant de trouver le handle d’un objet enfant de Shell_TrayWnd
- SendMessage: Fonction servant à rafraichir l’objet sélectionner (et dans notre cas, le SysTray)
Pour identifier tout ces objets, j’ai utilisé l’outil Spy++
J’ai réalisé un petit programme en C# pour tester tout ca:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Public CONST int WM_PAINT = 0xF;
[DllImport("USER32.DLL", EntryPoint="FindWindowEx")]
public static extern int FindWindowExA(int hWnd1, int hWnd2, string lpsz1, string lpsz2);
[DllImport("USER32.DLL", EntryPoint = "FindWindow")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("USER32.DLL", EntryPoint="SendMessage")]
public static extern int SendMessageb(int hwnd, int msg, int character, int lpsText);
private void btn_run_Click(object sender, EventArgs e)
{
int shellTrayWnd = FindWindow("shell_traywnd",null);
int trayNotifyWnd = FindWindowExA(shellTrayWnd, 0, "TrayNotifyWnd", null);
int sysPager = FindWindowExA(trayNotifyWnd, 0, "SysPager", null);
int tbWin32 = FindWindowExA(sysPager, 0, "ToolbarWindow32", null);
int restult = SendMessageb(tbWin32, WM_PAINT, 0, 0);
} |
Malheureusement, la fonction SendMessageb ne rafraichit rien et j’ai essayé sur les 3 objets: TrayNotifyWnd, SysPager et ToolbarWindow32 mais sans succès.
J’ai donc abandonné cette voie.
B. Solution Bricolage
Beaucoup de personne sur le net, cherchent également une solution à ce problème et certains ont émis l’idée de simuler le mouvement de souris sur la zone du SysTray.
Je suis donc partit dans cette voie, à regret.
Elle fonctionne, mais ce n’est pas des plus élégants.
C. Conclusion
Microsoft a laissé une zone pratiquement non contrôlable qui est le System Tray. Je reste convaincu qu’il y a surement un moyen de rafraichir cette zone via les API, mais pour le moment, je n’ai pas encore trouvé.