代码之家  ›  专栏  ›  技术社区  ›  Benoit

如何以编程方式重新启动Windows资源管理器进程

  •  7
  • Benoit  · 技术社区  · 16 年前

    我正在处理一个Windows Shell扩展,不幸的是,当对dll进行更改时,我必须重新启动Windows资源管理器(因为它将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.P.S.我正在使用.NET进行开发,但是shell重启功能可以是C、C++或.NET语言。它只是一个小型的独立可执行文件。

    8 回复  |  直到 6 年前
        1
  •  6
  •   Benoit    16 年前

    万无一失的解决方案:

    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");
    
        2
  •  10
  •   Chuck Rostance    12 年前

    在分析了前面的一些答案并做了一些研究之后,我在C中创建了一个完整的例子。这将关闭资源管理器外壳,然后等待它完全关闭并重新启动。希望这有帮助,在这个线程中有很多有趣的信息。

    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
  •  6
  •   CappuccinoRob    13 年前

    我注意到没有人解决将explorer.exe作为shell启动的问题,而不仅仅是打开一个explorer窗口。我花了一段时间才弄明白,其实很简单:

    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.useShellExecute设置为true才能使其作为shell重新启动。

        4
  •  1
  •   sharptooth    16 年前

    找到后,请使用GetWindowThreadProcessID,然后打开进程,然后终止进程。

        5
  •  1
  •   Benoit    16 年前

    在谷歌搜索之后,我想出了以下解决方案:

    
    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");
    }
    
        6
  •  1
  •   Bob Moore    16 年前

    这对我在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);
    

    但我找不到任何方法来抑制打开的“探索”窗口(我尝试过,因此软件隐藏)。在Vista上,在没有参数的情况下运行explorer.exe似乎与在早期系统上运行“explorer.exe/e”相同。你得自己在XP上试试,我这里没有。

    注意:使用TerminateProcess似乎很极端,但是在Explorer附近发布wm_会引发Windows关闭对话框。

        7
  •  1
  •   vhanla    13 年前

    这是为Windows7/8(和需要测试,甚至可能在Vista上工作)。

    自从 有一种关闭资源管理器的正确方法 (progman)包含在Windows 7&8中- 右键单击 任务栏(Win8中的shell traywind或Win7中的startmenu) 按ctrl-shift时 ,在弹出菜单中显示 关闭资源管理器的隐藏选项 ,并使用spy++挖掘它,它是由消息触发的 WMU用户+ 436 .

    所以我做了测试,并做了以下工作,效果很好。

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

    它关闭资源管理器,并打开所有实例。要重新启动资源管理器,请使用上面提供的方法。

    所以, 请确认 如果这在32位/64位版本的Windows Vista/7/8或任何其他版本上都有效,请发表评论。

        8
  •  0
  •   dalek9    15 年前

    一个C解决方案,它提供了更多的确定性,即“正确”的探索者进程会被杀死。

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