2009-02-19 8 views
6

Ich arbeite an einer Windows-Shell-Erweiterung, und leider, wenn ich Änderungen an der DLL, muss ich Windows Explorer neu starten (da es die DLL im Speicher hält).Wie Windows Explorer-Prozess programmatisch starten

Ich fand dieses Programm von Dino Esposito, aber es funktioniert nicht für mich.

 

void SHShellRestart(void) 
{ 
    HWND hwnd; 
    hwnd = FindWindow("Progman", NULL); 
    PostMessage(hwnd, WM_QUIT, 0, 0); 
    ShellExecute(NULL, NULL, "explorer.exe", NULL, NULL, SW_SHOW); 
    return; 
} 

Hat jemand etwas, das sie teilen können, um dies zu tun?

P.S. Ich weiß, dass ich zum Aufgabenmanager gehen und den Explorer-Prozess beenden kann, aber ich möchte es nur auf die faule Art tun. Außerdem ermöglicht dies eine Automatisierung.

P.P.S Ich verwende .NET für die Entwicklung, aber die Shell-Neustart-Funktionalität könnte in C, C++ oder einer .NET-Sprache sein. Es wird einfach eine kleine eigenständige ausführbare Datei sein.

Antwort

4

Eine narrensichere Lösung:

foreach (Process p in Process.GetProcesses()) 
{ 
    // In case we get Access Denied 
    try 
    { 
     if (p.MainModule.FileName.ToLower().EndsWith(":\\windows\\explorer.exe")) 
     { 
      p.Kill(); 
      break; 
     } 
    } 
    catch 
    { } 
} 
Process.Start("explorer.exe"); 
+2

Ein bisschen Fehler in der Logik. Sie werden einen neuen Explorer-Prozess für jede löschen Sie neu starten. Setzen Sie process.Start außerhalb der Foreach. – Benoit

+1

Oh ja, Entschuldigung :) – wj32

1

Verwenden Sie nach FindWindow GetWindowThreadProcessId, dann OpenProcess und dann TerminateProcess.

1

Nach etwas mehr googeln, kam ich mit der folgenden C# Lösung:


using System.Diagnostics; 
... 
static public void RestartExplorer() 
{ 
    foreach(Process p in Process.GetProcesses()) { 
     if(p.MainModule.ModuleName.contains("explorer") == true) 
     p.Kill(); 
    } 
    Process.Start("explorer.exe"); 
} 
+0

Das ist meistens das Gleiche, erfordert aber .NET. – sharptooth

+0

Wahr, aber wie ich eine .NET-Anwendung mache, ist das kein Problem – Benoit

+0

Zwei Punkte dann. Erstens, es ist besser zu prüfen, ob die Groß-/Kleinschreibung nicht mit "explorer.exe" übereinstimmt, um nicht gelegentlich in die SMT zu stoßen, die zufälligerweise den "explorer" Teilstring enthält. Auch werden Sie bitte die Frage bearbeiten, um explizit zu sagen, dass Sie .NET verwenden, so dass ich die Frage neu verfasse? – sharptooth

1

Dies funktioniert für mich auf Vista:

DWORD dwPID; 
HANDLE hExp; 
HWND hSysTray = ::FindWindow (TEXT("Shell_TrayWnd"), NULL) ; 
GetWindowThreadProcessId (hSysTray, &dwPID); 
hExp = OpenProcess (PROCESS_TERMINATE, FALSE, dwPID); 

if (hExp) 
{ 
    TerminateProcess (hExp, 0); 
} 
Sleep (2000); 
ShellExecute (NULL, NULL, TEXT("explorer.exe"), NULL, NULL, SW_HIDE); 

Aber ich kann keinen Weg finden, das zu unterdrücken Erkunden Sie das Fenster, das sich öffnet (ich habe es versucht, daher SW_HIDE). Unter Vista scheint die Ausführung von explorer.exe ohne Parameter identisch zu sein mit der Ausführung von "explorer.exe/e" auf früheren Systemen. Sie müssen es auf XP selbst ausprobieren, ich habe es hier nicht.

Hinweis: Die Verwendung von TerminateProcess scheint extrem, aber das Senden eines WM_CLOSE zum Explorer führt zu einem Dialogfeld zum Herunterfahren des Windows.

+0

Sorry für Nekro. ShellExecute funktioniert nicht auf Windows7/8 - Dateikopieren und Symbol-Overlays sind nach der Ausführung gebrochen, scheint keine Art und Weise zu optimieren ShellExecute Args zu helfen. Jedoch einfach stdlib.h System ("Start Explorer") Aufruf scheint korrekt Explorer wieder zu starten. –

0

A C# Lösung, die mehr Sicherheit bietet, dass die "richtigen" Explorer-Prozesse getötet.

6

Ich bemerkte, dass niemand das Problem ansprach, explorer.exe als Shell zu starten, anstatt nur ein Explorer-Fenster zu öffnen. Dauerte eine Weile, um dies herauszufinden, stellt sich heraus, es war etwas einfach:

string explorer = string.Format("{0}\\{1}", Environment.GetEnvironmentVariable("WINDIR"), "explorer.exe"); 
     Process process = new Process(); 
     process.StartInfo.FileName = explorer; 
     process.StartInfo.UseShellExecute = true; 
     process.Start(); 

Sie haben die StartInfo.UseshellExecute als wahr zu setzen, um es als das Shell neu zu starten zu bekommen.

+0

Dieser arbeitete für mich auf Windows 7 – marifrahman

+0

Arbeitete für mich in Windows 8.1. Vielen Dank! –

1

Dies ist für Windows 7/8 (und muss getestet werden, funktioniert vielleicht sogar unter Vista).

Seit gibt es eine richtige Art und Weise Explorer (progman) in Windows 7 & 8 enthalten zu schließen - nach rechts die Taskleiste (Shell_TrayWnd in Win8 oder StartMenu auf Win7) bei gedrückter Ctrl-Shift, darauf klicken zeigt im Popup-Menü eine versteckte Option zum Schließen Explorer, und Graben mit Spy ++ es wird durch die Nachricht ausgelöst WM_USER + 436.

Also habe ich getestet und das folgende funktioniert es super.

PostMessage(FindWindow('Shell_TrayWnd'),nil),WM_USER+436,0,0); 

Es schließt Explorer, mit allen geöffneten Instanzen. Verwenden Sie die oben beschriebenen Methoden, um den Explorer neu zu starten.

Also, bitte bestätigen Sie in Kommentaren, wenn dies auf 32bit/64bit-Editionen Ihrer Windows Vista/7/8 oder andere funktioniert.

+0

Funktioniert nicht auf win7 64. Es schließt Explorer, aber nicht wieder geöffnet. – itsho

+0

@itsho: Es ist nicht erlaubt, den Explorer in einer Windows-Version erneut zu öffnen. So funktioniert es auf Win7 64. Wie OP sagte, müssten Sie dann eine andere Methode verwenden, um den Explorer wieder zu öffnen. – gregschlom

+0

@gregschlom: Sie haben Recht. mein Fehler. – itsho

9

Nachdem ich einige der früheren Antworten analysiert und ein wenig Nachforschungen angestellt habe, habe ich ein kleines vollständiges Beispiel in C# erstellt. Dies schließt die Explorer-Shell und wartet darauf, dass sie vollständig heruntergefahren und neu gestartet wird. Hoffe, das hilft, es gibt viele interessante Informationen in diesem Thread.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 
using System.Threading; 

namespace RestartExplorer 
{ 
class Program 
{ 
    [DllImport("user32.dll", SetLastError = true)] 
    static extern bool PostMessage(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] uint Msg, IntPtr wParam, IntPtr lParam); 

    [DllImport("user32.dll", SetLastError = true)] 
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 

    const int WM_USER = 0x0400; //http://msdn.microsoft.com/en-us/library/windows/desktop/ms644931(v=vs.85).aspx 

    static void Main(string[] args) 
    { 
     try 
     { 
      var ptr = FindWindow("Shell_TrayWnd", null); 
      Console.WriteLine("INIT PTR: {0}", ptr.ToInt32()); 
      PostMessage(ptr, WM_USER + 436, (IntPtr)0, (IntPtr)0); 

      do 
      { 
       ptr = FindWindow("Shell_TrayWnd", null); 
       Console.WriteLine("PTR: {0}", ptr.ToInt32()); 

       if (ptr.ToInt32() == 0) 
       { 
        Console.WriteLine("Success. Breaking out of loop."); 
        break; 
       } 

       Thread.Sleep(1000); 
      } while (true); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("{0} {1}", ex.Message, ex.StackTrace); 
     } 
     Console.WriteLine("Restarting the shell."); 
     string explorer = string.Format("{0}\\{1}", Environment.GetEnvironmentVariable("WINDIR"), "explorer.exe"); 
     Process process = new Process();   
     process.StartInfo.FileName = explorer; 
     process.StartInfo.UseShellExecute = true; 
     process.Start(); 

     Console.ReadLine(); 

    } 
} 
} 
+0

Sehr schön, ich habe genommen, was Sie getan haben und eine statische Klasse für die Verwendung in einer Winform-Anwendung gemacht und es funktioniert perfekt auf Windows 7 Pro 64 Bit –

+0

Es scheint, dies ist die einzige richtige Möglichkeit zum Herunterfahren des Explorers. Aber ich frage mich, was ist WM_USER + 436 Nachricht? Es ist eine Art undokumentierte Funktion? –

Verwandte Themen