That does not seem to be correct. The documentation indicates APC [1] can only occur from a waiting/blocking state. So, the program is in a consistent state and can only be on a few known instructions, unlike signals. As such, most functions should be safe to call.
This is more like select() sometimes calling a user-supplied function in addition to checking for I/O.
> A thread enters an alertable state when it calls the SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx, or WaitForSingleObjectEx function.
So this is a lot less like Unix signals. It only really works if the thread you're doing the async procedure call to is one that's likely to use those.
So APCs are safe enough -- a lot safer than Unix signal handlers.
I see, I read the docs slightly too quickly. Still, though, I would have expected a conspicuous warning about exceptions in those calls, because MS is in on C++ (so they can't hide behind "but we expected only C") and apparently(?) the APC machinery doesn't catch and block exceptions in user code.
This is more like select() sometimes calling a user-supplied function in addition to checking for I/O.
[1] https://learn.microsoft.com/en-us/windows/win32/sync/asynchr...