![](/img/trans.png)
[英]log4net became very slow with caller location information after Windows 10 Fall Creators Update (1709)
[英]Gracefully restarting explorer.exe as of Windows 10 1709, Fall Creators Update aka Redstone 3
对于Windows 10 1703的当前版本(创建者更新),我有一个叫C#的小应用在安装过程中被要求重新启动explorer.exe。 这是为了帮助刷新任务栏/注册表项,以便安装后虚拟外设之一将出现在任务栏上,而无需重新启动。
using System;
using System.Diagnostics;
namespace RestartExplorer
{
class Program
{
static int Main(string[] args)
{
var process = Process.GetProcessesByName("explorer")[0];
process.Kill();
Process.Start("explorer");
return 0;
}
}
}
这在Redstone 2中工作正常,但在当前的Insiders Preview Windows 10 1709 Redstone 3内部版本16294.1.170916-2023
,它不仅杀死了浏览器外壳,而且还杀死了所有打开的文件浏览器窗口。 这是一种超级侵入式操作,如果在发生这种情况时我在工作时打开了十几个窗口,我认为我对UX不会感到很高兴。
我验证了在CTRL + SHIFT 右键单击 “ 退出资源管理器”的任务栏上也显示了相同的差异行为,而不仅仅是我的小应用程序。
因此,如果我要确保用户的窗口不会丢失,那么现在应该如何重新启动资源管理器,或者更好的方法是,有没有一种更好的方法来获得我想要做的最终结果?
使用重新启动管理器API关闭所有打开的资源管理器。 它将重新启动所有已关闭的服务器。 唯一的缺点是重新启动的应用程序将被激活,因此您必须围绕应用程序失去焦点进行编码。
参见https://msdn.microsoft.com/zh-cn/library/windows/desktop/aa373649(v=vs.85).aspx
var sessionKey = Guid.NewGuid().ToString();
NativeMethods.RmStartSession(out IntPtr session, 0, sessionKey).CheckError();
try
{
NativeMethods.RmRegisterResources(session, 1, new[] { Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe") }, 0, null, 0, null).CheckError();
NativeMethods.RmShutdown(session, 0, null).CheckError();
NativeMethods.RmRestart(session, 0, null).CheckError();
}
finally
{
NativeMethods.RmEndSession(session);
}
您还将需要以下NativeMethods
public static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
internal struct RM_UNIQUE_PROCESS
{
public int dwProcessId;
public com.FILETIME ProcessStartTime;
}
[Flags]
internal enum RM_SHUTDOWN_TYPE : uint
{
RmForceShutdown = 0x1,
RmShutdownOnlyRegistered = 0x10
}
internal delegate void RM_WRITE_STATUS_CALLBACK(UInt32 nPercentComplete);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
internal static extern int RmStartSession(out IntPtr pSessionHandle, int dwSessionFlags, string strSessionKey);
[DllImport("rstrtmgr.dll")]
internal static extern int RmEndSession(IntPtr pSessionHandle);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
internal static extern int RmRegisterResources(IntPtr pSessionHandle, UInt32 nFiles, string[] rgsFilenames, UInt32 nApplications, RM_UNIQUE_PROCESS[] rgApplications, UInt32 nServices, string[] rgsServiceNames);
[DllImport("rstrtmgr.dll")]
internal static extern int RmShutdown(IntPtr pSessionHandle, RM_SHUTDOWN_TYPE lActionFlags, RM_WRITE_STATUS_CALLBACK fnStatus);
[DllImport("rstrtmgr.dll")]
internal static extern int RmRestart(IntPtr pSessionHandle, int dwRestartFlags, RM_WRITE_STATUS_CALLBACK fnStatus);
[DllImport("kernel32.dll")]
internal static extern bool GetProcessTimes(IntPtr hProcess, out com.FILETIME lpCreationTime, out com.FILETIME lpExitTime, out com.FILETIME lpKernelTime, out com.FILETIME lpUserTime);
}
基于@Tim代码并在此处提供了更有用的示例,这是我刚刚编写的用于与Restart Manager交互的类:
https://gist.github.com/falahati/34b23831733151460de1368c5fba8e93
这是一个例子:
using RestartManager;
public static class Test
{
public static void Main()
{
using (var rm = new RestartManagerSession())
{
// add all processes having the name `explorer`
rm.RegisterProcess(Process.GetProcessesByName("explorer"));
// you can also add explorer.exe specifically by
// using the `RegisterProcessFile()` method
//rm.RegisterProcessFile(new FileInfo(Path.Combine(
// Environment.GetFolderPath(Environment.SpecialFolder.Windows),
// "explorer.exe"
//)));
rm.Shutdown(RestartManagerSession.ShutdownType.Normal);
rm.Restart();
}
}
}
如果您想更具体一些,还可以使用以下代码来获取Explorer的主要过程:
[DllImport("user32")]
private static extern IntPtr GetShellWindow();
[DllImport("user32", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr windowHandle, out uint processId);
public static Process GetShellProcess()
{
try
{
var shellWindowHandle = GetShellWindow();
if (shellWindowHandle != IntPtr.Zero)
{
GetWindowThreadProcessId(shellWindowHandle, out var shellPid);
if (shellPid > 0)
{
return Process.GetProcessById((int) shellPid);
}
}
}
catch (Exception)
{
// ignored
}
return null;
}
然后,使用同一类通过Restart Manager重新启动它。 无论如何,它比Process.GetProcessesByName("explorer")[0]
更好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.