在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重新启动管理器对话框中禁用“不关闭应用程序”选项
每次用VS启动魔兽时总是出现explorer.exe 应用程序错误的对话框,然后就玩不了!不得不不强制关机!