Как программно перезапустить процесс проводника Windows
-
05-09-2019 - |
Вопрос
Я работаю над расширением оболочки Windows, и, к сожалению, при внесении изменений в DLL я должен перезапустить Windows Explorer (поскольку он хранит DLL в памяти).
Я нашел эту программу у Дино Эспозито, но у меня она не работает.
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;
}
Есть ли у кого-нибудь что-нибудь, чем они могли бы поделиться, чтобы сделать это?
P.S.Я понимаю, что могу зайти в диспетчер задач и завершить процесс Explorer, но я просто хочу сделать это ленивым способом.Кроме того, это обеспечивает автоматизацию.
P.P.S Я использую .NET для разработки, но функциональность перезапуска оболочки может быть на C, C ++ или языке .NET.Это будет просто небольшой автономный исполняемый файл.
Решение
Надежное решение:
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");
Другие советы
Проанализировав некоторые из предыдущих ответов и проведя небольшое исследование, я создал небольшой законченный пример на C #.Это закрывает оболочку explorer, затем ожидает ее полного завершения и перезапускает.Надеюсь, это поможет, в этой теме много интересной информации.
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();
}
}
}
Я заметил, что никто не рассматривал проблему запуска explorer.exe как оболочку, а не просто открывал окно проводника.Мне потребовалось некоторое время, чтобы разобраться в этом, оказывается, это было что-то простое:
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();
Вы должны установить StartInfo.Используйте ShellExecute как true, чтобы перезапустить его как оболочку.
После FindWindow используйте GetWindowThreadProcessId, затем OpenProcess, затем TerminateProcess .
Еще немного погуглив, я пришел к следующему решению на 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");
}
Это работает для меня в 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);
Но я не могу найти никакого способа отключить открывающееся окно explore (я пытался, отсюда и SW_HIDE).В Vista запуск explorer.exe без параметров, похоже, такой же, как запуск "explorer.exe / e" в более ранних системах.Вам придется попробовать это самостоятельно на XP, у меня здесь этого нет.
Примечание:Использование TerminateProcess действительно кажется экстремальным, но отправка WM_CLOSE в explorer вызывает диалоговое окно завершения работы Windows.
Это для Windows 7/8 (и нуждается в тестировании, возможно, даже работает на Vista).
С тех пор как существует правильный способ закрыть Проводник (progman) включен в Windows 7 и 8 - щелкнув правой кнопкой мыши панель задач (Shell_TrayWnd в Win8 или StartMenu в Win7) при нажатии Ctrl-Shift, это отображается во всплывающем меню скрытая опция для закрытия Проводника, и копая его с помощью Spy ++ , он запускается сообщением WM_USER+436.
Итак, я протестировал и, выполнив следующее, он отлично работает.
PostMessage(FindWindow('Shell_TrayWnd'),nil),WM_USER+436,0,0);
Он закрывает Проводник со всеми открытыми экземплярами.А чтобы перезапустить explorer, используйте методы, описанные выше.
Итак, пожалуйста, подтвердите в комментариях, работает ли это в 32-разрядных / 64-разрядных версиях вашей Windows vista / 7 / 8 или любой другой.
Решение на C #, которое обеспечивает большую уверенность в том, что "правильные" процессы Explorer будут уничтожены.
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);
}