Impact: Failure to check against a NULL value and dereferencing it
leads to a crash in `explorer.exe` with fault offset 0xfc69 on
22621-based OS builds. This happens when right clicking certain system
tray icons, like "Epic Games Launcher" when using the Windows 11
taskbar.
Description: The issue has been addressed with improved checks: a check
against NULL values is performed before attempting to work with the
data the variables might point to.
This commit includes support for the Windows spotlight feature from
22000.708+ OS builds.
Related to this, ExplorerPatcher now offers the following functionality:
* Hide the "Learn about this picture" icon
* Choose which items from the Windows spotlight icon context menu to
have replicated in the desktop context menu (legacy context menu only)
* Set a schedule for "Switch to next picture"
* Manipulate the feature from the Properties UI, bypassing the desktop
icon
sign out process when using the weather widget
The hang was happening because the UI thread of explorer was hanging in
`dllmain!PeopleBand_DrawTextWithGlowHook` in a call to `AcquireSRWLockExclusive`
when the host process for the widget terminated (due to the system shutting
down - the case when hr is 0x800706ba aka "RPC server is unavailable"). When the
remote process dies, say we are in `dllmain!PeopleBand_DrawTextWithGlowHook`;
a call to some interface from it hangs for a bit, and during
that time the calling thread is able to continue its lifetime, during which a
subsequent call to `dllmain!PeopleBand_DrawTextWithGlowHook` is made (another
widget redraw is requested). As SRW locks do not really support recursion (calling
the same function from the same thread), this behavior is then expected and the
whole thing hangs, thus hanging the shutdown process (and explorer's UI thread in
turn). That's why when you clicked "Cancel" when the UI to close hung apps was
displayed at shutdown, you returned to a frozen desktop. Apparently, Windows lets
explorer hang indefinitely at shutdown, which made matters even worse.
The solution is two fold:
* Widget destruction is dispatched to the service thread. This is not strictly
necessary, but allows for better control of where the thing is destroyed from.
* Switched from SRW locks to a critical section, which is a per-thread lock. All
this has to do is make sure the program destroys the widget only when no other
routine (usually drawing stuff) uses it.
This should pretty much mitigate the issue, hopefully.