在MSI安装期间重新启动Explorer.exe不起作用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在MSI安装期间重新启动Explorer.exe不起作用相关的知识,希望对你有一定的参考价值。

我有一个Visual Studio安装项目,它创建一个MSI来安装我的应用程序。我的应用程序有一个带有图标覆盖处理程序的shell扩展,因此需要重新启动explorer.exe才能使图标覆盖处理程序开始工作。我已经注册了一个自定义操作,以便在使用以下方法重新启动资源管理器的提交上运行:

public static void restartExplorer()
{
    //stop the shell
    try
    {
       Process process1 = new Process();
       ProcessStartInfo startInfo = new ProcessStartInfo();
       startInfo.WindowStyle = ProcessWindowStyle.Hidden;
       startInfo.FileName = "CMD.exe";
       startInfo.Arguments = "/C "taskkill /f /im explorer.exe"";
       process1.StartInfo = startInfo;
       process1.Start();
       do
        {
          Thread.Sleep(100);
          if (process1.HasExited)
          {
               break;
          }
         } while (true);
        }
        catch (Exception e)
        {
            Log.Error("restart explorer", e.StackTrace);
        }

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

    }

当我从visual studio测试并从命令行调用它时,此方法很有效,但是在安装或卸载期间从MSI调用它时,它会停止资源管理器,但不会重新启动它。

有没有人知道为什么它会在所有情况下都有效,除非在安装或卸载期间由MSI调用?

有没有人有另一种方法在安装/卸载期间从MSI重新启动资源管理器?

答案

杀死探险家有点粗糙...我建议你使用Restart Manager API。好处是资源管理器知道如何重新启动它,它将在重新启动后恢复所有打开的窗口。这是一个C#实用程序类,它将为您完成。只需在自定义操作中调用此方法:

...
var rm = new RestartManager();
rm.RestartExplorerProcesses();

...

/// <summary>
/// A utility class to restart programs the most gracefully possible. Wraps Windows <see href="https://msdn.microsoft.com/en-us/library/windows/desktop/cc948910.aspx">Restart Manager API</see>. This class cannot be inherited.
/// </summary>
public sealed class RestartManager
{
    /// <summary>
    /// The default kill timeout value (2000).
    /// </summary>
    public const int DefaultKillTimeout = 2000;

    /// <summary>
    /// The default retry count value (10).
    /// </summary>
    public const int DefaultRetryCount = 10;

    /// <summary>
    /// The default retry timeout value (100).
    /// </summary>
    public const int DefaultRetryTimeout = 100;

    /// <summary>
    /// Initializes a new instance of the <see cref="RestartManager"/> class.
    /// </summary>
    public RestartManager()
    {
        KillTimeout = DefaultKillTimeout;
        RetryCount = DefaultRetryCount;
        RetryTimeout = DefaultRetryTimeout;
    }

    /// <summary>
    /// Gets or sets the kill timeout in ms.
    /// </summary>
    /// <value>The kill timeout.</value>
    public int KillTimeout { get; set; }

    /// <summary>
    /// Gets or sets the retry count.
    /// </summary>
    /// <value>The retry count.</value>
    public int RetryCount { get; set; }

    /// <summary>
    /// Gets or sets the retry timeout in ms.
    /// </summary>
    /// <value>The retry timeout.</value>
    public int RetryTimeout { get; set; }

    /// <summary>
    /// Restarts the Windows Explorer processes.
    /// </summary>
    /// <param name="stoppedAction">The stopped action.</param>
    public void RestartExplorerProcesses() => RestartExplorerProcesses(null, false, out var error);

    /// <summary>
    /// Restarts the Windows Explorer processes.
    /// </summary>
    /// <param name="stoppedAction">The stopped action.</param>
    public void RestartExplorerProcesses(ContextCallback stoppedAction) => RestartExplorerProcesses(stoppedAction, false, out var error);

    /// <summary>
    /// Restarts the Windows Explorer processes.
    /// </summary>
    /// <param name="stoppedAction">The stopped action.</param>
    /// <param name="throwOnError">if set to <c>true</c> errors may be throw in case of Windows Restart Manager errors.</param>
    public void RestartExplorerProcesses(ContextCallback stoppedAction, bool throwOnError) => RestartExplorerProcesses(stoppedAction, throwOnError, out var error);

    /// <summary>
    /// Restarts the Windows Explorer processes.
    /// </summary>
    /// <param name="stoppedAction">The stopped action.</param>
    /// <param name="throwOnError">if set to <c>true</c> errors may be throw in case of Windows Restart Manager errors.</param>
    /// <param name="error">The error, if any.</param>
    public void RestartExplorerProcesses(ContextCallback stoppedAction, bool throwOnError, out Exception error)
    {
        var explorers = Process.GetProcessesByName("explorer").Where(p => IsExplorer(p)).ToArray();
        Restart(explorers, stoppedAction, throwOnError, out error);
    }

    /// <summary>
    /// Restarts the processes locking a specific file.
    /// </summary>
    /// <param name="path">The file path.</param>
    /// <param name="stoppedAction">The stopped action.</param>
    /// <param name="throwOnError">if set to <c>true</c> errors may be throw in case of Windows Restart Manager errors.</param>
    /// <param name="error">The error, if any.</param>
    /// <exception cref="ArgumentNullException">path is null.</exception>
    public void RestartProcessesLockingFile(string path, ContextCallback stoppedAction, bool throwOnError, out Exception error)
    {
        if (path == null)
            throw new ArgumentNullException(nameof(path));

        var lockers = GetLockingProcesses(path, false, throwOnError, out error);
        if (error != null)
            return;

        Restart(lockers, stoppedAction, throwOnError, out error);
    }

    /// <summary>
    /// Restarts the Windows Explorer processes locking a specific file.
    /// </summary>
    /// <param name="path">The file path.</param>
    /// <param name="stoppedAction">The stopped action.</param>
    /// <param name="throwOnError">if set to <c>true</c> errors may be throw in case of Windows Restart Manager errors.</param>
    /// <param name="error">The error, if any.</param>
    /// <exception cref="ArgumentNullException">path is null.</exception>
    public void RestartExplorerProcessesLockingFile(string path, ContextCallback stoppedAction, bool throwOnError, out Exception error)
    {
        if (path == null)
            throw new ArgumentNullException(nameof(path));

        var processes = GetLockingProcesses(path, false, throwOnError, out error);
        if (error != null)
            return;

        var explorers = processes.Where(p => IsExplorer(p)).ToArray();
        Restart(explorers, stoppedAction, throwOnError, out error);
    }

    /// <summary>
    /// Determines whether the specified process is Windows Explorer.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <returns><c>true</c> if the specified process is Windows Explorer; otherwise, <c>false</c>.</returns>
    public static bool IsExplorer(Process process)
    {
        if (process == null)
            return false;

        string explorerPath = Path.Combine(Environment.GetEnvironmentVariable("windir"), "explorer.exe");
        return string.Compare(process.MainModule.FileName, explorerPath, StringComparison.OrdinalIgnoreCase) == 0;
    }

    /// <summary>
    /// Gets a list of processes locking a specific file.
    /// </summary>
    /// <param name="filePath">The file path.</param>
    /// <param name="onlyRestartable">if set to <c>true</c> list only restartable processes.</param>
    /// <param name="throwOnError">if set to <c>true</c> errors may be throw in case of Windows Restart Manager errors.</param>
    /// <param name="error">The error, if any.</param>
    /// <returns>A list of processes.</returns>
    /// <exception cref="ArgumentNullException">filePath is null.</exception>
    public IReadOnlyList<Process> GetLockingProcesses(string filePath, bool onlyRestartable, bool throwOnError, out Exception error)
    {
        if (filePath == null)
            throw new ArgumentNullException(nameof(filePath));

        return GetLockingProcesses(new[] { filePath }, onlyRestartable, throwOnError, out error);
    }

    // NOTE: file name comparison seems to be case insensitive
    /// <summary>
    /// Gets a list of processes locking a list of specific files.
    /// </summary>
    /// <param name="filePaths">The files paths.</param>
    /// <param name="onlyRestartable">if set to <c>true</c> list only restartable processes.</param>
    /// <param name="throwOnError">if set to <c>true</c> errors may be throw in case of Windows Restart Manager errors.</param>
    /// <par

以上是关于在MSI安装期间重新启动Explorer.exe不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何在MSI Installshield重新启动管理器对话框中禁用“不关闭应用程序”选项

使用 C++ 重新启动 explorer.exe

每次用VS启动魔兽时总是出现explorer.exe 应用程序错误的对话框,然后就玩不了!不得不不强制关机!

Windows后登陆没有图形界面只有cmd,explorer.exe不能启动

explorer.exe命令行

Bundle 可以在安装期间从本地文件夹中引用 MSI 吗?