Summary
After explorer.exe restarts (crash, Windows Update, or a manual shell restart), the tray icon and the embedded taskbar widget disappear, even though the process is still running. The only current workaround is to kill and relaunch the app — exactly what #34 reported ("I killed the process and re-ran the command and it shows fine now, not sure what the issue was").
Root cause
The widget embeds itself as a child of Shell_TrayWnd (via SetParent). When Explorer restarts, the taskbar window is destroyed, which destroys our child window outright — afterwards IsWindow(hwnd) returns false and GetParent returns 0. The UI thread is then stuck in GetMessageW with no window left, so:
WM_TIMER is never delivered again,
- inter-thread
SendMessage to the destroyed window is a no-op,
- the
"TaskbarCreated" broadcast never reaches us (a destroyed/child window doesn't receive it).
Confirmed empirically: a window-timer watchdog stops firing the instant Explorer restarts, and IsWindow on the widget handle is false afterwards while the process keeps running.
Reproduction
- Run the widget (it embeds into the taskbar).
- Restart Explorer (
taskkill /f /im explorer.exe, or Task Manager -> Restart Windows Explorer).
- The process is still alive, but the tray icon and widget are gone until a manual relaunch.
Proposed fix
A dedicated watchdog thread (independent of the dead message loop) polls the Shell_TrayWnd handle; when it changes (Explorer restarted), it relaunches the widget as a fresh process that re-embeds into the new taskbar. The relaunched child waits on the single-instance mutex until the old instance exits, with a throttle to avoid a relaunch storm if Explorer is crash-looping.
In-process recovery isn't viable here because the window is genuinely destroyed and the UI thread can't recreate it from another thread; a clean relaunch is the robust path.
I have this implemented and tested (survives repeated Explorer restarts, re-embeds correctly each time). Happy to open a PR if you're open to this approach — or to a different one (e.g. in-process window recreation) if you'd prefer.
Summary
After
explorer.exerestarts (crash, Windows Update, or a manual shell restart), the tray icon and the embedded taskbar widget disappear, even though the process is still running. The only current workaround is to kill and relaunch the app — exactly what #34 reported ("I killed the process and re-ran the command and it shows fine now, not sure what the issue was").Root cause
The widget embeds itself as a child of
Shell_TrayWnd(viaSetParent). When Explorer restarts, the taskbar window is destroyed, which destroys our child window outright — afterwardsIsWindow(hwnd)returnsfalseandGetParentreturns0. The UI thread is then stuck inGetMessageWwith no window left, so:WM_TIMERis never delivered again,SendMessageto the destroyed window is a no-op,"TaskbarCreated"broadcast never reaches us (a destroyed/child window doesn't receive it).Confirmed empirically: a window-timer watchdog stops firing the instant Explorer restarts, and
IsWindowon the widget handle isfalseafterwards while the process keeps running.Reproduction
taskkill /f /im explorer.exe, or Task Manager -> Restart Windows Explorer).Proposed fix
A dedicated watchdog thread (independent of the dead message loop) polls the
Shell_TrayWndhandle; when it changes (Explorer restarted), it relaunches the widget as a fresh process that re-embeds into the new taskbar. The relaunched child waits on the single-instance mutex until the old instance exits, with a throttle to avoid a relaunch storm if Explorer is crash-looping.In-process recovery isn't viable here because the window is genuinely destroyed and the UI thread can't recreate it from another thread; a clean relaunch is the robust path.
I have this implemented and tested (survives repeated Explorer restarts, re-embeds correctly each time). Happy to open a PR if you're open to this approach — or to a different one (e.g. in-process window recreation) if you'd prefer.