优雅地退出资源管理器(以编程方式)
如何以编程方式优雅关闭资源管理器?
我的意思是,如何以编程方式调用此函数:
编辑:图片中的拼写错误,应该显示“Ctrl- Shift-右键单击”而不是“Shift-单击”。
How do you gracefully close Explorer programmatically?
By that I mean, how do you invoke this function programmatically:
Edit: Typo in the picture, it should say "Ctrl-Shift-Right-Click" instead of "Shift-Click".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
出于好奇我对此进行了调试。它所做的只是向资源管理器的一个窗口发布一条消息:
当然,这是一条未记录的 WM_USER 消息,因此该行为将来很可能会发生变化。
I debugged this out of curiosity. All it does is post a message to one of explorer's windows:
Of course this is an undocumented WM_USER message so the behavior could quite possibly change in the future.
@Luke:首先感谢您对Shell_TrayWnd的0x5B4用户消息的详细分析和提示!
不幸的是,该方法有两个缺点:首先,它使用未记录的用户消息,在未来的 Windows 版本中可能会更改,其次,它在 Windows XP 下不起作用,因为退出 Windows 的“神奇过程”不同(打开关闭对话框,然后按 SHIFT 取消它) -CTRL-ALT-ESC)并且那里不涉及消息发布。
如果有一种可靠且可移植的方法来从另一个进程中干净地终止资源管理器,无论 Windows 版本如何,那就太好了。因此,我继续调试干净地终止资源管理器的代码的反汇编,以便找到有关如何实现此目标的提示。我仍然没有完美的解决方案,但我做了一些有趣的观察(在 Windows 7 和 Windows XP 上),我想与可能感兴趣的人分享:
Windows 7
0x5B4 消息最终得到处理通过 CTray::_DoExitExplorer 方法。如果启用了符号服务器,则可以分别在
{,,explorer.exe}CTray::_DoExitExplorer
(Visual Studio 语法)中设置断点。
explorer!CTray::_DoExitExplorer
(windbg 语法)Windows XP
在 WinXP 中,您必须在
{,,explorer.exe}CTray::_ExitExplorerCleanly 设置断点
(视觉工作室语法)分别。
explorer!CTray::_ExitExplorer
(windbg 语法),然后在关闭对话框中输入“神奇按键”(SHIFT-CTRL-ALT-ESC)。从反汇编中可以看出,这两种方法非常相似(请参阅后续帖子)。伪代码是
注意,第一个 PostMessage() 调用将 TRUE 作为 lParam 传递,WM_QUIT 正式未使用该值。 lParam的含义好像是bShutdown == TRUE。
当然,从另一个应用程序设置 g_fFakeShutdown 是不可能的(或不可行)。因此,我测试了 PostMessage(hWndProgMan, WM_QUIT, 0, TRUE/FALSE) 后跟或不跟 PostMessage(hWndTray, WM_QUIT, 0, FALSE) 的不同组合。看来资源管理器在 Windows XP 和 Windows 7 下显示出不同的行为。
以下两种方法似乎是在 Windows XP 下终止资源管理器的良好候选方法。不幸的是,它们在 Windows 7 下不起作用:
Windows XP 中的行为
在这两种情况下,shell (explorer.exe) 都会终止,并且在终止之前它会设置注册表项
(可以使用 Sysinternals Process Monitor 观察到),或者通过在 {,,explorer}_WriteCleanShutdown@4 (分别为 explorer!_WriteCleanShutdown)处设置断点。
Windows 7 中的行为
两种方法都不起作用:尽管 shell 似乎已终止,但 explorer.exe 进程仍在运行。
备注
如果我仅使用 lParam = TRUE 将 WM_QUIT 发布到 hWndProgMan,而不将消息发布到 hWndTray,即,
我会得到一个有趣的行为(Win7 和 WinXP):出现关闭对话框。如果取消它,一切看起来都很正常,但两三(!)秒后,资源管理器终止。
结论
也许最好的解决方案是将 ExitExplorer() 与 Windows 7 中未记录的 WM_USER 函数一起使用,对于 Windows XP 则使用 ExitExplorer1() 或 ExitExplorer2() 。这两种 XP 方法中的任何一种是否比另一种具有优势?我不知道。
附录
CTray::_DoExitExplorer (Windows 7) 和 CTray::_ExitExplorerCleanly (Windows XP) 的反汇编
Windows 7
('bUnnamedVariable' 是地址 g_fInSizeMove+4 处的模块全局变量)
Windows XP
('bUnnamedVariable' 似乎是 CTray 相对偏移量的成员440h)
备注
看来 WM_QUIT 在这里以一种非常不标准的方式使用,比较以下来自 MSDN 的摘录 MSDN 上的 WM_QUIT
@Luke: first of all, thanks for the detailed analysis and the hint about the 0x5B4 user message to the Shell_TrayWnd!
Unfortunately, the method has two drawbacks; First, it uses an undocumented user message, which may change in future Windows versions, and second, it does not work under Windows XP, since the 'magic procedure' to exit windows is different (open the shutdown dialog, then cancel it pressing SHIFT-CTRL-ALT-ESC) and no message posting is involved there.
It would be nice to have a reliable and portable way to terminate explorer cleanly from another process regardless of the windows version. So I continued debugging into the disassembly of the code which terminates explorer cleanly in order to find a hint about how I could achieve this. I still don't have the perfect solution but I made some interesting observations (on Windows 7 and Windows XP) which I want to share with whoever might be interested:
Windows 7
The 0x5B4-message is eventually handled by the method CTray::_DoExitExplorer. If you have symbol server enabled, then you can set a breakpoint in
{,,explorer.exe}CTray::_DoExitExplorer
(visual studio syntax)resp.
explorer!CTray::_DoExitExplorer
(windbg syntax)Windows XP
In WinXP, you have to set your breakpoint at
{,,explorer.exe}CTray::_ExitExplorerCleanly
(visual studio syntax)resp.
explorer!CTray::_ExitExplorer
(windbg syntax)before you enter the 'magic keystrokes' (SHIFT-CTRL-ALT-ESC) at the shutdown dialog. Both methods are very similar, as you can see from the disassembly (see followup post). The pseudo code is
Note that the first PostMessage() call passes TRUE as lParam, which is officially unused by WM_QUIT. The meaning of the lParam seems to be bShutdown == TRUE.
Of course it is impossible (or not feasible) to set g_fFakeShutdown from another application. So I tested different combinations of PostMessage(hWndProgMan, WM_QUIT, 0, TRUE/FALSE) followed or not by PostMessage(hWndTray, WM_QUIT, 0, FALSE). It seems that explorer shows different behaviour under Windows XP and Windows 7.
The following two methods seem to be good candidates to terminate explorer under windows XP. Unfortunately they don't work under Windows 7:
Behaviour in Windows XP
In both cases the shell (explorer.exe) terminates and before terminating it sets the registry key
as can be observed using Sysinternals Process Monitor, or by setting a breakpoint at {,,explorer}_WriteCleanShutdown@4 (resp. explorer!_WriteCleanShutdown).
Behaviour in Windows 7
Both methods don't work: although it appears that the shell terminated, the explorer.exe process is still running.
Remark
If I only post a WM_QUIT to hWndProgMan with lParam = TRUE without posting a message to hWndTray, i.e.,
then I get an interesting behaviour (both Win7 and WinXP): The shutdown dialog appears. If you cancel it, everything appears to be normal, but after two or three (!) seconds, explorer terminates.
Conclusion
Maybe the best solution is to use ExitExplorer() with the undocumented WM_USER function for Windows 7 and either ExitExplorer1() or ExitExplorer2() for Windows XP. Does any one of the two XP-methods have advantages over the other? I don't know.
Appendix
Disassembly of CTray::_DoExitExplorer (Windows 7) and CTray::_ExitExplorerCleanly (Windows XP)
Windows 7
('bUnnamedVariable' is a module global variable at address g_fInSizeMove+4)
Windows XP
('bUnnamedVariable' seems to be a member of CTray at relative offset 440h)
Remark
It seems that WM_QUIT is used here in a very non-standard way, compare the following excerpt from MSDN WM_QUIT on MSDN
在 Windows Vista 及更高版本上,您可以使用 RestartManager API 正常关闭资源管理器。
在伪代码中,它看起来像这样:
On Windows Vista and above, you can use RestartManager API to gracefully shutdown explorer.
In pseudocode it will look like this:
我不认为资源管理器可以“优雅地”关闭。 EnumProcesses ->比较路径-> TerminateProcess
编辑:尝试发送 WM_CLOSE /WM_QUIT (http://support.microsoft.com/kb/178893) 或 结束任务
I don't think explorer can be closed "Gracefully". EnumProcesses -> compare path -> TerminateProcess
Edit: Try to send WM_CLOSE/WM_QUIT (http://support.microsoft.com/kb/178893) or EndTask