You can do this before calling CefShutdown.
Alternatively, just in case application (let's call it app.exe), for example, crashes and the input desktop remains in your custom one, you can have an additional helper app (app_helper.exe) doing something like this:
- app:
1. starts app_helper running in the default desktop (CreateProcess(Ex) and set STARTUPINFO lpDesktop to L"WinSta0\\Default") with some argument like --parent-pid=GetCurrentProcessId() (the helper can anyway do a CreateToolhelp32Snapshot and find the parent process)
2. create an event name "app.ProcessTerminate.<pid>"
3. run
- app_helper:
1. get the parent pid (and determine if is really app.exe) => parent_pid
2. OpenProcess on parent_pid with SYCNHRONIZE (PROCESS_QUERY_INFORMATION if you plan to call later GetExitCodeProcess - see below) => parent_process
3. format the event name "app.ProcessTerminate.<parent_pid>", and do OpenEvent with SYNCHRONIZE => parent_process_terminate_event
4a. WaitForSingleObject(parent_process, INFINITE) or WaitForSingleObject(parent_process_terminate_event, INFINITE) if you just do wait on parent process or parent process termination event
4b. wait for app termination with loop: create an invisible window and do a message loop similar to this:
- Code: Select all
bool need_restore_desktop = false;
bool end_loop = false;
while(!end_loop) {
DWORD wait_result = MsgWaitForMultipleObjects(1, &pprocess, FALSE, INFINITE, QA_ALLINPUT);
if(wait_result == WAIT_OBJECT_0) {
end_loop = true;
// parent process or parent process term event signaled; possibly call here GetExitCodeProcess
need_restore_desktop = true;
break;
}
else if(wait_result == WAIT_OBJECT_0 + 1) {
MSG msg;
while(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg); // optional
DispatchMessage(&msg);
if(msg.message == WM_ENDSESSION) {
// Windows is shuttin, but read below *
need_restore_desktop = true;
end_loop = true;
}
}
}
// ...
}
if(need_restore_desktop) {
RestoreDesktop(); // see below
}
4. OpenInputDesktop and GetUserObjectInformation(with UOI_NAME) to determine the name of the input desktop
4a. if it is the default desktop, do nothing and close
4b. if it is *not* the default desktop, then OpenDesktop on the default desktop and SwitchDesktop to the default desktop handle.
A sample implementation of desktop restoring could be simply this (inside app_helper):
- Code: Select all
void RestoreDesktop() {
HDESK hDefaultDesktop = GetThreadDesktop(GetCurrentThreadId()); // we know we run in default; or if doubt, OpenDesktop on WinSta0\Default
if(hDefaultDesktop != NULL) {
SwitchDesktop(hDefaultDesktop);
CloseDesktop(hDefaultDesktop);
}
}
WM_ENDSESSION (and WM_QUERYENDSESSION) caveats.
*Sometimes* (yes, I know) WM_(QUERY)ENDSESSION do NOT arrive on the message loop of the application running in a non-default desktop. I saw this on Windows 7, although I did not checked thoroughly on this later.
I do have a mechanism that traps these messages in the helper app running in the default desktop and forward them in the non-default desktop via IPC so the non-default desktop app can close (otherwise all sorts of nastiness happened, at least at that time when I notices this).
Hope that helps.