Normalement La Sortie De L'Explorateur (Par Programmation)
Comment normalement fermer l'Explorateur par programmation?
je veux dire Par là, comment vous appelez cette fonction de base du programme:
Edit: tapez sur l'image "Ctrl-Shift-Right-Click" au lieu de "Shift-Click".
4 réponses
Je l'ai débogué par curiosité. Tout ce qu'il fait est de poster un message à l'une des fenêtres de l'Explorateur:
BOOL ExitExplorer()
{
HWND hWndTray = FindWindow(_T("Shell_TrayWnd"), NULL);
return PostMessage(hWndTray, 0x5B4, 0, 0);
}
bien sûr, il s'agit d'un message WM_USER non documenté donc le comportement pourrait très probablement changer dans le futur.
@Luke: tout d'abord, merci pour l'analyse détaillée et l'indication sur le message de l'utilisateur 0x5B4 au Shell_TrayWnd!
malheureusement, la méthode a deux inconvénients; D'abord, elle utilise un message utilisateur non documenté, qui peut changer dans les versions futures de Windows, et deuxièmement, elle ne fonctionne pas sous Windows XP, puisque la 'procédure magique' pour quitter windows est différente (ouvrir la boîte de dialogue d'arrêt, puis l'annuler en appuyant sur SHIFT-CTRL-ALT-ESC) et aucun affichage de message n'est impliqué y.
il serait bien d'avoir un moyen fiable et portable pour terminer l'Explorateur proprement d'un autre processus indépendamment de la version de windows. J'ai donc continué à déboguer dans le démontage du code qui termine l'Explorateur proprement afin de trouver un indice sur la façon dont je pourrais réaliser ceci. Je n'ai toujours pas la solution parfaite mais j'ai fait quelques observations intéressantes (sur Windows 7 et Windows XP) que je veux partager avec qui que ce soit intéressés:
Windows 7
le message 0x5B4-est éventuellement traité par la méthode CTray:: _DoExitExplorer. Si vous avez activé le serveur de symboles, alors vous pouvez définir un point de rupture dans
{,,explorer.exe}CTray::_DoExitExplorer
(syntaxe visual studio)
resp.
explorer!CTray::_DoExitExplorer
(syntaxe windbg)
Windows XP
dans WinXP, vous devez définir votre point de rupture à
{,,explorer.exe}CTray::_ExitExplorerCleanly
(visuel syntaxe de studio)
resp.
explorer!CTray::_ExitExplorer
(syntaxe windbg)
avant d'entrer les 'touches magiques' (SHIFT-CTRL-ALT-ESC) dans la boîte de dialogue d'arrêt. Les deux méthodes sont très similaires, comme vous pouvez le voir à partir du démontage (voir post de suivi). Le pseudo code est
if (bUnnamedVariable == FALSE) {
g_fFakeShutdown = TRUE; // (1)
PostMessage(hWndProgMan, WM_QUIT, 0, TRUE); // (2)
if (PostMessage(hWndTray, WM_QUIT, 0, 0)) { // (3)
bUnnamedVariable = TRUE;
}
}
notez que le premier appel PostMessage() passe TRUE comme lParam, qui est officiellement inutilisé par WM_QUIT. La signification du lParam semble être bShutdown == VRAI.
bien sûr, il est impossible (ou impossible) de définir g_fFakeShutdown à partir d'une autre application. J'ai donc testé différentes combinaisons de PostMessage(hWndProgMan, WM_QUIT, 0, TRUE/FALSE) suivi ou non de PostMessage (Hwndtray, WM_QUIT, 0, FALSE). Il semble que l'Explorateur montre un comportement différent sous Windows XP et Windows 7.
les deux méthodes suivantes semblent être de bons candidats pour terminer l'explorateur sous windows XP. Malheureusement, ils ne fonctionnent pas sous Windows 7:
BOOL ExitExplorer1() {
HWND hWndProgMan = FindWindow(_T("Progman"), NULL);
PostMessage(hWndProgMan, WM_QUIT, 0, TRUE); // <= lParam == TRUE !
HWND hWndTray = FindWindow(_T("Shell_TrayWnd"), NULL);
PostMessage(hWndTray, WM_QUIT, 0, 0);
return TRUE;
}
BOOL ExitExplorer2() {
HWND hWndProgMan = FindWindow(_T("Progman"), NULL);
PostMessage(hWndProgMan, WM_QUIT, 0, FALSE); // <= lParam == FALSE !
return TRUE;
}
Comportement dans Windows XP
dans les deux cas, le shell (explorer.exe) se termine et avant de terminer, il définit la clé de registre
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\CleanShutdown = TRUE
comme on peut l'observer en utilisant Sysinternals Process Monitor, ou en définissant un point de rupture à {,,explorer}_WriteCleanShutdown@4 (resp. explorer!_WriteCleanShutdown).
comportement dans Windows 7
les Deux méthodes ne fonctionnent pas: bien qu'il semble que la coquille se termine, l'Explorateur.le processus exe est toujours en cours.
Remarque
Si je ne publier une WM_QUIT à hWndProgMan avec lParam = TRUE sans poster un message à hWndTray, c'est à dire,
BOOL ExitExplorer3() {
HWND hWndProgMan = FindWindow(_T("Progman"), NULL);
PostMessage(hWndProgMan, WM_QUIT, 0, TRUE);
return TRUE;
}
puis j'obtiens un comportement intéressant (à la fois Win7 et WinXP): la boîte de dialogue shutdown apparaît. Si vous annulez, tout semble être normal, mais après deux ou trois (!) secondes, l'explorateur se termine.
Conclusion
peut-être que la meilleure solution est D'utiliser ExitExplorer() avec la fonction wm_user non documentée pour Windows 7 et ExitExplorer1() ou ExitExplorer2() pour Windows XP. L'une des deux méthodes XP présente-t-elle des avantages par rapport à l'autre? Je ne sais pas.
Annexe
démontage de CTray:: _DoExitExplorer (Windows 7) et CTray:: _ExitExplorerCleanly (Windows XP)
Windows 7
{,,explorer.exe}CTray::_DoExitExplorer:
explorer!CTray::_DoExitExplorer:
00fdde24 833df027020100 cmp dword ptr [explorer!g_fInSizeMove+0x4 (010227f0)],0 ds:0023:010227f0=00000000
00fdde2b 53 push ebx
00fdde2c 8bd9 mov ebx,ecx
00fdde2e 7535 jne explorer!CTray::_DoExitExplorer+0x41 (00fdde65)
00fdde30 56 push esi
00fdde31 8b35ec14f700 mov esi,dword ptr [explorer!_imp__PostMessageW (00f714ec)]
00fdde37 57 push edi
00fdde38 33ff xor edi,edi
00fdde3a 47 inc edi
00fdde3b 57 push edi
00fdde3c 6a00 push 0
00fdde3e 6a12 push 12h
00fdde40 ff35e8000201 push dword ptr [explorer!v_hwndDesktop (010200e8)]
00fdde46 893ddc270201 mov dword ptr [explorer!g_fFakeShutdown (010227dc)],edi
00fdde4c ffd6 call esi
00fdde4e 6a00 push 0
00fdde50 6a00 push 0
00fdde52 6a12 push 12h
00fdde54 ff7304 push dword ptr [ebx+4]
00fdde57 ffd6 call esi
00fdde59 85c0 test eax,eax
00fdde5b 7406 je explorer!CTray::_DoExitExplorer+0x3f (00fdde63)
00fdde5d 893df0270201 mov dword ptr [explorer!g_fInSizeMove+0x4 (010227f0)],edi
00fdde63 5f pop edi
00fdde64 5e pop esi
00fdde65 a1f0270201 mov eax,dword ptr [explorer!g_fInSizeMove+0x4 (010227f0)]
00fdde6a 5b pop ebx
00fdde6b c3 ret
('bUnnamedVariable' est un module variable globale à l'adresse g_fInSizeMove+4)
Windows XP
{,,explorer.exe}CTray::_ExitExplorerCleanly:
01031973 8B FF mov edi,edi
01031975 57 push edi
01031976 8B F9 mov edi,ecx
01031978 83 BF 40 04 00 00 00 cmp dword ptr [edi+440h],0
0103197F 75 35 jne CTray::_ExitExplorerCleanly+43h (10319B6h)
01031981 53 push ebx
01031982 56 push esi
01031983 8B 35 94 17 00 01 mov esi,dword ptr [__imp__PostMessageW@16 (1001794h)]
01031989 33 DB xor ebx,ebx
0103198B 43 inc ebx
0103198C 53 push ebx
0103198D 6A 00 push 0
0103198F 6A 12 push 12h
01031991 FF 35 8C 60 04 01 push dword ptr [_v_hwndDesktop (104608Ch)]
01031997 89 1D 48 77 04 01 mov dword ptr [_g_fFakeShutdown (1047748h)],ebx
0103199D FF D6 call esi
0103199F 6A 00 push 0
010319A1 6A 00 push 0
010319A3 6A 12 push 12h
010319A5 FF 77 04 push dword ptr [edi+4]
010319A8 FF D6 call esi
010319AA 85 C0 test eax,eax
010319AC 74 06 je CTray::_ExitExplorerCleanly+41h (10319B4h)
010319AE 89 9F 40 04 00 00 mov dword ptr [edi+440h],ebx
010319B4 5E pop esi
010319B5 5B pop ebx
010319B6 8B 87 40 04 00 00 mov eax,dword ptr [edi+440h]
010319BC 5F pop edi
010319BD C3 ret
('bUnnamedVariable" semble être un membre de CTray à l'offset relatif 440h)
Remarque Il semble que WM_QUIT est utilisé ici d'une manière très non-standard, comparez L'extrait suivant de MSDN WM_QUIT on MSDN
Ce message n'a pas de retour valeur parce qu'elle cause le message boucle à terminer avant le message est envoyé à la fenêtre de la demande procédure.
Remarques le message WM_QUIT n'est pas associé à une fenêtre et donc ne sera jamais reçu par un de la fenêtre de procédure de fenêtre. Il est récupéré seulement par le GetMessage ou Fonctions de PeekMessage.
ne pas poster le message WM_QUIT utiliser la fonction PostMessage; utiliser PostQuitMessage.
sur Windows Vista et au-dessus, vous pouvez utiliser RestartManager API pour arrêter l'explorateur avec grâce.
En pseudo-code, il ressemblera à ceci:
RmStartSession(...);
RM_UNIQUE_PROCESS[] processes = GetProcesses("explorer.exe"); // get special handles to process you want to close
RmRegisterResources(processes); // register those processes with restart manager session
RmShutdown(RM_SHUTDOWN_TYPE.RmForceShutdown);
RmRestart(...); // restart them back, optionally
RmEndSession(...);
je ne pense pas que l'explorateur peut être fermé "Normalement". EnumProcesses - > comparer le chemin -> TerminateProcess
Edit: Essayez d'envoyer le message WM_CLOSE/WM_QUIT (http://support.microsoft.com/kb/178893) ou EndTask