Como programaticamente o Windows reiniciar o Process Explorer
-
05-09-2019 - |
Pergunta
Eu estou trabalhando em um Windows shell extensão, e, infelizmente, ao fazer alterações para a DLL, I deve reiniciar o Windows Explorer (uma vez que mantém a DLL na memória).
Eu encontrei este programa a partir Dino Esposito, mas ele não funciona para mim.
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;
}
Será que qualquer um tem algo que eles podem compartilhar a fazer isso?
P.S. Eu percebo que eu posso ir para o gerenciador de tarefas e matar o processo explorer, mas eu só quero fazê-lo da maneira preguiçosa. Além disso, este permite a automação.
P.P.S Estou usando .NET para o desenvolvimento, mas a funcionalidade de reinicialização shell poderia estar em C, C ++ ou uma linguagem .NET. Será simplesmente um pequeno executável autônomo.
Solução
Uma solução fool-proof:
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");
Outras dicas
Depois de analisar algumas das respostas anteriores e fazer um pouco de pesquisa, eu criei um pequeno exemplo completo em C #. Isso fecha o shell explorador então espera por ele para desligar completamente e reinicia-lo. Espero que isso ajude, há um monte de informações interessantes neste segmento.
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();
}
}
}
notei ninguém abordou a questão da explorer.exe começando como o shell, em vez de apenas abrir uma janela do Explorer. Levei um tempo para descobrir isso, acaba que era algo simples:
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();
Você tem que definir o StartInfo.UseshellExecute como verdade para obtê-lo para reiniciar como o shell.
Depois de FindWindow uso GetWindowThreadProcessId, em seguida, OpenProcess, então TerminateProcess.
Depois de mais alguns googling, eu vim com a solução C # seguinte:
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");
}
Isso funciona para mim no 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);
Mas eu não consigo encontrar nenhuma maneira de suprimir a janela de explorar que se abre (eu tentei, daí o SW_HIDE). No Vista, correndo explorer.exe sem parâmetros parece ser o mesmo que correr "explorer.exe / e" em sistemas anteriores. Você vai ter que experimentar por si próprio no XP, eu não tê-lo aqui.
Nota:. Usando TerminateProcess parece extremo, mas postar um WM_CLOSE para explorer provoca um diálogo janelas de desligamento
Esta é para o Windows 7/8 (e teste de necessidade, talvez até mesmo funciona em Vista).
Desde há uma maneira correta de perto Explorador (progman) incluído no Windows 7 & 8 - com o botão direito na barra de tarefas (Shell_TrayWnd em Win8 ou StartMenu no Win7) enquanto pressiona Ctrl-Shift , ele mostra no menu pop-up uma opção escondida para perto Explorador , e cavando-lo usando Spy ++ que é desencadeada por mensagem WM_USER + 436 .
Então, eu testei e fazendo o seguinte ele funciona muito bem.
PostMessage(FindWindow('Shell_TrayWnd'),nil),WM_USER+436,0,0);
Ele fecha Explorer, com todas as instâncias abertas. E explorador relançamento, usar os métodos fornecidos acima.
Assim, Por favor, confirme nos comentários se isso funciona em 32bit / 64bit edições do seu Windows Vista / 7/8 ou qualquer outro.
A C solução # que fornece mais certeza de que os processos explorador "certas" ser morto.
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);
}