Discussion:
Restarting Explorer Programmatically without executing registry RUN sections
(too old to reply)
Anthony Wieser
2004-10-22 06:43:09 UTC
Permalink
I'm trying to programmatically restart Explorer, and have found the
following snippet on MSDN (Q137572)

HWND hwndShell = FindWindow("Progman", NULL);
PostMessage(hwndShell, WM_QUIT, 0, 0L);
WinExec("Explorer.exe",SW_SHOW);

I've also found this as a way to shut down the shell:

Press CTRL+ALT+SHIFT, and click No in the Shut Down Windows dialog box.
On Windows 2000,
click Cancel instead of No. The Shell is now shut down, but all other
applications are still running,
including the debugger.

Then in task manager, run explorer.exe

My question is:

When I use the first way, everything in the Run keys of the registry and the
start menu are executed again, while using the second method, this does not
happen. Does anybody know what is happening in the second method that
prevents the running of the auto run entries? Is there any way to mimic the
behaviour in my program?

Anthony Wieser
Wieser Software Ltd
Jim Barry
2004-10-22 10:38:57 UTC
Permalink
Post by Anthony Wieser
When I use the first way, everything in the Run keys of the registry and the
start menu are executed again, while using the second method, this does not
happen. Does anybody know what is happening in the second method that
prevents the running of the auto run entries?
When Explorer runs, it creates a registry key called StartupHasBeenRun under a key named after the current session ID in [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\SessionInfo]. When Explorer exits, it removes the key. If the key already exists when Explorer starts, then it knows that it must have previously crashed or been terminated, so it skips running the startup items.
Post by Anthony Wieser
Is there any way to mimic the behaviour in my program?
Instead of posting a WM_QUIT to Explorer, just kill it with TerminateProcess. That way, it doesn't get a chance to remove the StartupHasBeenRun key.

DWORD pid = 0;
GetWindowThreadProcessId(FindWindow(_T("Progman"), NULL), &pid);
if (pid)
{
if (HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid))
{
TerminateProcess(h, 0);
CloseHandle(h);
}
}
--
Jim Barry, MVP for Windows SDK
Jim Barry
2004-10-22 11:10:02 UTC
Permalink
Post by Jim Barry
Instead of posting a WM_QUIT to Explorer, just kill it with TerminateProcess.
It occurs to me that you might still need to kill off the secondary Explorer process if the user has the "Launch folder windows in a separate process" setting enabled, or if "DesktopProcess" is set in the registry. It would be possible to enumerate the top-level windows and close any that have the class name "ExploreWClass". However, as we know, that may not be enough to make Explorer exit, so it would still be necessary to enumerate the running processes and terminate any lingering Explorer process.
--
Jim Barry, MVP for Windows SDK
Anthony Wieser
2004-10-22 12:24:04 UTC
Permalink
I've now managed to succesfully write the key back on Windows XP using:

HKEY hk3 = NULL;
::RegCreateKeyEx(hk2, "StartupHasBeenRun", 0, NULL,
REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hk3, NULL);

Volatile being the key to it, which I found in a previous response to
another of your posts, however there doesn't seem to be a corresponding key
in WIndows 98? Are there similar keys in previous versions of the OS (95,
98 and ME)?

I'll have to look into the behavior when you have separate processes.

Anthony Wieser
Wieser Software ltd
Post by Jim Barry
Instead of posting a WM_QUIT to Explorer, just kill it with
TerminateProcess.
It occurs to me that you might still need to kill off the secondary Explorer
process if the user has the "Launch folder windows in a separate process"
setting enabled, or if "DesktopProcess" is set in the registry. It would be
possible to enumerate the top-level windows and close any that have the
class name "ExploreWClass". However, as we know, that may not be enough to
make Explorer exit, so it would still be necessary to enumerate the running
processes and terminate any lingering Explorer process.
--
Jim Barry, MVP for Windows SDK
Jim Barry
2004-10-22 15:48:22 UTC
Permalink
Post by Anthony Wieser
Volatile being the key to it, which I found in a previous response to
another of your posts, however there doesn't seem to be a corresponding key
in WIndows 98? Are there similar keys in previous versions of the OS (95,
98 and ME)?
I'm afraid I don't know - I've been avoiding Win9x like the plague for years ;-)
--
Jim Barry, MVP for Windows SDK
Anthony Wieser
2004-10-22 21:49:41 UTC
Permalink
There seems to be no way to to do it on 9x. Even doing it with the keyboard
sequence causes the start sequence to run, so I guess my strategy is:

Graceful Shutdown on NT/2000/XP with registry reconstruction for
Windows\CurrentVersion\Explorer\SessionInfo
Terminate Process on 9X, with registry hack of
CurrentVersion\Explorer\FaultKey to stop ActiveDesktop complaining.

Thanks for your feedback. It's a pity these simple things take so long to
figure out.

Anthony Wieser
Wieser Software Ltd

p.s. Sorry about the top post--any idea why replies to your messages with
OE6 don't get marked with >?
Post by Anthony Wieser
Volatile being the key to it, which I found in a previous response to
another of your posts, however there doesn't seem to be a corresponding key
in WIndows 98? Are there similar keys in previous versions of the OS (95,
98 and ME)?
I'm afraid I don't know - I've been avoiding Win9x like the plague for years
;-)
--
Jim Barry, MVP for Windows SDK
Jim Barry
2004-10-27 12:21:14 UTC
Permalink
Post by Anthony Wieser
Graceful Shutdown on NT/2000/XP
Actually there is nothing very graceful about posting WM_QUIT ;-)
Post by Anthony Wieser
p.s. Sorry about the top post--any idea why replies to your messages with
OE6 don't get marked with >?
Probably because I post using the quoted-printable MIME encoding.
--
Jim Barry, MVP for Windows SDK
Anthony Wieser
2004-10-28 14:23:14 UTC
Permalink
Post by Anthony Wieser
Graceful Shutdown on NT/2000/XP
Actually there is nothing very graceful about posting WM_QUIT ;-)
Surely it's slightly more graceful than TerminateProcess.

Anthony Wieser
Wieser Software Ltd
Jim Barry
2004-10-28 15:50:22 UTC
Permalink
Post by Anthony Wieser
Surely it's slightly more graceful than TerminateProcess.
Well, perhaps in the sense that post-message-loop code gets to run before the process terminates. However, windows aren't destroyed, and applications don't generally expect their message loops to randomly exit, responding with an access violation in some cases. It's arguably better just to put the thing out of its misery with TerminateProcess :-)
--
Jim Barry, MVP for Windows SDK
Tim Robinson
2004-10-28 20:48:14 UTC
Permalink
Post by Jim Barry
Post by Anthony Wieser
Surely it's slightly more graceful than TerminateProcess.
Well, perhaps in the sense that post-message-loop code gets to run
before the process terminates. However, windows aren't destroyed, and
applications don't generally expect their message loops to randomly
exit, responding with an access violation in some cases. It's
arguably better just to put the thing out of its misery with
TerminateProcess :-)
Also MSDN says you mustn't post WM_QUIT directly, but use PostQuitMessage.
--
Tim Robinson (MVP, Windows SDK)
http://mobius.sourceforge.net/
Anthony Wieser
2004-10-28 21:59:25 UTC
Permalink
"Tim Robinson" <***@nowhere.com> wrote in message news:***@uni-berlin.de...
: Jim Barry wrote:
: > Anthony Wieser wrote:
: >
: >>Surely it's slightly more graceful than TerminateProcess.
: >
: >
: > Well, perhaps in the sense that post-message-loop code gets to run
: > before the process terminates. However, windows aren't destroyed, and
: > applications don't generally expect their message loops to randomly
: > exit, responding with an access violation in some cases. It's
: > arguably better just to put the thing out of its misery with
: > TerminateProcess :-)
:
: Also MSDN says you mustn't post WM_QUIT directly, but use PostQuitMessage.
:
: --
: Tim Robinson (MVP, Windows SDK)
: http://mobius.sourceforge.net/

MSDN also say:

http://support.microsoft.com/default.aspx?scid=kb;en-us;137572

This article was previously published under Q137572

SUMMARY
Creating and updating shell extensions in Windows requires that the shell be
restarted. This may be accomplished by having the user manually perform this
task; however, in many cases, you may find it is better to do it
programmatically.
MORE INFORMATION
To restart the shell programmatically, find the shell window, post it a quit
message, and then call WinExec() with explorer.exe. For

Example:
HWND hwndShell = FindWindow("Progman", NULL);
PostMessage(hwndShell, WM_QUIT, 0, 0L);
WinExec("Explorer.exe",SW_SHOW);

Anthony WieserWieser Software Ltd

Anthony Wieser
2004-10-22 11:33:43 UTC
Permalink
Thanks for the reply. I tried the terminate process mechanism, but it has
the undesired effect of giving an ActiveDesktop recovery screen on windows
2000 if a jpg background has been set, so option 2 is out.

Also, it appears that the registry key you describe is restricted, so I
can't actually write it back to make it think it has run after I kill the
process. Any suggestions on that?

Finally, I tried sending the ProgMan window a WM_CLOSE, which pops up the
logoff dialog, and then used send input to send
VK_LSHIFT down
VK_LCONTROL down
VK_LMENU down
VK_ESCAPE down
VK_ESCAPE up
VK_LMENU up
VK_LCONTROL up
VK_LSHIFT up

but that didn't work either.

Anthony Wieser
Wieser Software Ltd
Post by Anthony Wieser
When I use the first way, everything in the Run keys of the registry and the
start menu are executed again, while using the second method, this does not
happen. Does anybody know what is happening in the second method that
prevents the running of the auto run entries?
When Explorer runs, it creates a registry key called StartupHasBeenRun under
a key named after the current session ID in
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\SessionInfo].
When Explorer exits, it removes the key. If the key already exists when
Explorer starts, then it knows that it must have previously crashed or been
terminated, so it skips running the startup items.
Post by Anthony Wieser
Is there any way to mimic the behaviour in my program?
Instead of posting a WM_QUIT to Explorer, just kill it with
TerminateProcess. That way, it doesn't get a chance to remove the
StartupHasBeenRun key.

DWORD pid = 0;
GetWindowThreadProcessId(FindWindow(_T("Progman"), NULL), &pid);
if (pid)
{
if (HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid))
{
TerminateProcess(h, 0);
CloseHandle(h);
}
}
--
Jim Barry, MVP for Windows SDK
Jim Barry
2004-10-22 15:46:02 UTC
Permalink
Post by Anthony Wieser
Thanks for the reply. I tried the terminate process mechanism, but it has
the undesired effect of giving an ActiveDesktop recovery screen on windows
2000 if a jpg background has been set, so option 2 is out.
Ah.
Post by Anthony Wieser
Finally, I tried sending the ProgMan window a WM_CLOSE, which pops up the
logoff dialog, and then used send input to send
[...]
Post by Anthony Wieser
but that didn't work either.
I guess GetKeyState will still report that these keys are up.
--
Jim Barry, MVP for Windows SDK
Loading...