9

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.

10 Answers 10

15

After parsing some of the earlier answers and doing a bit of research, I've created a little complete example in C#. This closes the explorer shell then waits for it to completely shut down and restarts it. Hope this helps, there's a lot of interesting info in this 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();

    }
}
}
3
  • Very nice, I took what you have done and made a static class for use within a winform's application and it works perfectly on Windows 7 Pro 64 bit Commented Dec 3, 2013 at 12:40
  • It seems this is the only proper way to shutdown explorer. But I wonder what is WM_USER + 436 message? It's kind of undocumented feature?
    – user6416335
    Commented Jul 4, 2017 at 13:07
  • @AlekDepler it's the same like CTRL+SHIFT+Right click on taskbar and choosing "Exit explorer" aka: a way to gracefully exit the windows shell process.
    – brz
    Commented Mar 12, 2018 at 18:39
7

I noticed no one addressed the issue of starting explorer.exe as the shell, rather than it just opening an explorer window. Took me a while to figure this out, turns out it was something simple:

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

You have to set the StartInfo.UseshellExecute as true to get it to restart as the shell.

0
5

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");
1
  • 2
    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
    Commented Mar 3, 2009 at 11:37
3

A method that is compatible with all systems

public static void RestartExplorer()
{
    using(Process p = new Process())
    {
        p.StartInfo = new ProcessStartInfo
        {
            FileName = "taskkill.exe",
            Arguments = "-f -im explorer.exe",
            WindowStyle = ProcessWindowStyle.Hidden,
            UseShellExecute = true,
            CreateNoWindow = true,
        };
        p.Start();
        p.WaitForExit();
        p.StartInfo = new ProcessStartInfo("explorer.exe");
        p.Start();
    }
}

If it's not a home version system, this can be done

public static void RestartExplorer()
{
    using(Process p = new Process())
    {
        p.StartInfo = new ProcessStartInfo
        {
            FileName = "tskill.exe",
            Arguments = "explorer",
            WindowStyle = ProcessWindowStyle.Hidden,
            UseShellExecute = true,
            CreateNoWindow = true,
        };
        p.Start();
        p.WaitForExit();
    }
}
1

After FindWindow use GetWindowThreadProcessId, then OpenProcess, then TerminateProcess.

1

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");
}
4
  • That's mostly the same, but requires .NET.
    – sharptooth
    Commented Feb 19, 2009 at 14:28
  • True, but as I'm doing a .NET Application, that's not an issue
    – Benoit
    Commented Feb 19, 2009 at 15:30
  • 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
    Commented Feb 20, 2009 at 14:45
  • 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 B
    Commented Feb 23, 2009 at 11:45
1

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.

1
  • Sorry for necroing. ShellExecute doesn't work on Windows7/8 -- file copying and icon overlays are broken after executing, no manner of tweaking ShellExecute args seems to help. However plain stdlib.h system("start explorer") call seems to correctly start explorer again. Commented Dec 22, 2014 at 17:51
1

This is for Windows 7/8 (and need testing, maybe even works on Vista).

Since there is a proper way to close Explorer (progman) included in Windows 7 & 8 - by right clicking the taskbar (Shell_TrayWnd in Win8 or StartMenu on Win7) while pressing Ctrl-Shift, it shows in the popup menu a hidden option to close Explorer, and digging it using Spy++ it is triggered by message WM_USER+436.

So I tested and doing the following it works great.

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

It closes Explorer, with all the opened instances. And to relaunch explorer, use the methods provided above.

So, please confirm in comments if this works on 32bit/64bit editions of your windows vista/7/8 or any other.

3
  • Doesn't work on win7 64. it DOES close Explroer, but not re-opens it.
    – itsho
    Commented Dec 4, 2011 at 22:14
  • @itsho: it is not supposed to re-open explorer on any Windows version. So it does work on Win7 64. As OP said, you'd then have to use another method to re-open explorer.
    – gregschlom
    Commented Jan 31, 2012 at 21:21
  • @itsho: Might be a very late reply, but for 64-bit Windows 7/8 the best and most reliable way to reopen explorer is to use stdlib.h system("start explorer"); call. Using ShellExecute leaves file copying and icon overlays broken. Commented Dec 22, 2014 at 17:51
1

Rather than trying to restart the explorer, you can quickly refresh it, and it should have a similar effect.

[DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);

public static void RefreshExplorer()
{
    SHChangeNotify(0x08000000, 0x00000000, IntPtr.Zero, IntPtr.Zero);
}

Just call RefreshExplorer() and it will refresh the explorer.

SHChangeNotify accept eventId as first parameter. In above example, it notifies that file association is changed, but you can do it for specific event. All the eventId constants are mentioned in the docs here. You can find their values in magnumdb.

2
  • Didn't do anything on my Windows 10 Commented Jun 27, 2022 at 11:42
  • It may not be idle for all use cases, for example, when I change Windows 11 modern context menu to standard and use this method to restart it didn't affect the state of context menu cause it requires restarting explorer process, but it is useful for some things like when I changed file association and triggered this. It immediately shows a new associated app for the file type.
    – Ravi Patel
    Commented Jun 28, 2022 at 10:35
0

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.