views:

1268

answers:

5

I'm working on a windows shell extension, and unfortunately, when making changes to the DLL, I must restart windows explorer (since it keeps the DLL in memory).

I found this program from Dino Esposito, but it doesn't work for 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;
}

Does any one have something they can share to do this?

P.S. I realize that I can go to task manager and kill the explorer process, but I just want to do it the lazy way. Besides, this enables automation.

P.P.S I am using .NET for the development, but the shell restart functionality could be in C, C++ or a .NET language. It will simply be a small stand-alone executable.

+1  A: 

After FindWindow use GetWindowThreadProcessId, then OpenProcess, then TerminateProcess.

sharptooth
+1  A: 

After some more googling, I came up with the following C# solution:


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");
}
Benoit
That's mostly the same, but requires .NET.
sharptooth
True, but as I'm doing a .NET Application, that's not an issue
Benoit
Two points then. First, it's better to test for case insensitive match with "explorer.exe" not to bump occasionally into smth that accidentially contains "explorer" substring. Also will you please edit the question to say explicitly that you use .NET so that I retag the question?
sharptooth
As sharptooth says, test for a complete match with "explorer.exe", otherwise you may end up killing processes that have 'explorer' in their name (Internet Explorer [thought that's more likely to be iexplore] and Windows Explorer spring to mind as basic problems).
James Burgess
+1  A: 

This works for me on 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);

But I can't find any way to suppress the explore window that opens (I tried, hence the SW_HIDE). On Vista, running explorer.exe without parameters seems to be the same as running "explorer.exe /e" on earlier systems. You'll have to try it for yourself on XP, I don't have it here.

Note: Using TerminateProcess does seem extreme, but posting a WM_CLOSE to explorer provokes a windows shutdown dialog.

Bob Moore
+2  A: 

A fool-proof solution:

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");
wj32
A bit of flaw in the logic. You'll restart a new explorer process for each one you delete. Put process.Start outside the foreach.
Benoit
Oh yes, sorry :)
wj32
A: 

A C# solution that provides more certainty that the "right" explorer processes get killed.

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