Domanda

Sto lavorando su un Windows Shell Extension, e, purtroppo, quando si apportano modifiche alla DLL, devo riavviare Windows Explorer (poiché mantiene la DLL in memoria).

Ho trovato questo programma da Dino Esposito, ma non funziona per me.

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;
}

Se uno ha qualcosa che possono condividere per fare questo?

P.S. Mi rendo conto che posso andare a Task Manager e uccidere il processo explorer, ma voglio solo farlo nel modo pigro. Inoltre, questo consente l'automazione.

P.P.S Sto usando .NET per lo sviluppo, ma la funzionalità di riavvio Shell potrebbe essere in C, C ++ o un linguaggio .NET. Sarà semplicemente un piccolo eseguibile autonomo.

È stato utile?

Soluzione

Una soluzione infallibile:

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");

Altri suggerimenti

Dopo l'analisi alcune delle risposte precedenti e facendo un po 'di ricerca, ho creato un po' di esempio completo in C #. Questo chiude la shell explorer quindi attende per spegnere completamente e lo riavvia. Spero che questo aiuti, c'è un sacco di informazioni interessanti in questo 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();

    }
}
}

ho notato nessuno ha affrontato il problema di explorer.exe partendo come shell, piuttosto che semplicemente aprire una finestra di Explorer. Mi ha portato un po 'per capirlo, scopre che era qualcosa di semplice:

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();

È necessario impostare la StartInfo.UseshellExecute come vero per farlo riavviare come shell.

Dopo FindWindow utilizzare GetWindowThreadProcessId, quindi OpenProcess, quindi TerminateProcess.

Dopo un po 'di più googling, mi si avvicinò con la seguente soluzione C #:


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");
}

Questo funziona per me su 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);

Ma non riesco a trovare un modo per sopprimere la finestra che si apre esplorare (ho provato, da cui lo SW_HIDE). Su Vista, in esecuzione explorer.exe senza parametri sembra essere la stessa cosa che lanciare "explorer.exe / e" sui sistemi precedenti. Dovrete provare di persona su XP, io non ce l'ho qui.

Nota: L'uso TerminateProcess non sembrare estremo, ma la pubblicazione di un WM_CLOSE a explorer provoca una finestra di dialogo Windows Shutdown

.

Questo è per Windows 7/8 (e hanno bisogno di prove, forse funziona anche su Vista).

Da esiste un modo corretto di chiudere Explorer (Progman) incluso in Windows 7 & 8 - facendo clic destro nella barra delle applicazioni (Shell_TrayWnd in Win8 o StartMenu su Win7) mentre premendo Ctrl-Maiusc , si vede nel menu a comparsa un'opzione nascosta per chiudere Explorer , e scavando utilizzando Spy ++ è innescato dal messaggio WM_USER + 436 .

Così ho provato e facendo il seguente funziona benissimo.

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

Si chiude Explorer, con tutte le istanze aperte. E per rilanciare Explorer, utilizzare i metodi sopra riportati.

Quindi, si prega di confermare nei commenti se questo funziona su edizioni a 32 bit / 64 bit di Windows Vista / 7/8 o qualsiasi altro.

Una soluzione C # che fornisce maggiore certezza che i processi esploratore "giuste" vengono uccisi.

using System;
using System.Diagnostics;

...............

public static void RestartExplorer()
 {
 const string explorer = "explorer.exe";
 string explorerPath = string.Format("{0}\\{1}", Environment.GetEnvironmentVariable("WINDIR"), explorer);
 foreach (Process process in Process.GetProcesses())
  {
  // In case we get Access Denied
  try
   {
   if (string.Compare(process.MainModule.FileName, explorerPath, StringComparison.OrdinalIgnoreCase) == 0)
    {
    process.Kill();
    }
   }
  catch
   {
   }
  }
 Process.Start(explorer);
 }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top