从Windows 10 1709,Fall Creators Update又名Redstone 3开始,正常重启explorer.exe

时间:2017-09-26 22:07:12

标签: c# windows-10 registry explorer

对于当前版本的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中,它不会杀死资源管理器外壳,它会杀死所有打开文件浏览器窗口。这是超级侵入性的,如果我在工作时打开了几十个窗户,我就不会觉得我对用户体验非常满意。

我在 退出资源管理器 <的任务栏上验证了 CTRL + SHIFT 右键单击 / strong>也表现出相同的分歧行为,而不仅仅是我的小应用程序。

所以,如果我想确保我的用户&#39;窗户并没有全部丢失,我现在应该如何重新启动资源管理器,或者更好的是,是否有更好的方法来获得我想要做的最终结果?

2 个答案:

答案 0 :(得分:2)

使用重新启动管理器API关闭所有打开的资源管理器。它会重新启动任何已关闭的。唯一的缺点是重启应用程序将被激活,因此您必须围绕您的应用程序编码而失去焦点。

请参阅https://msdn.microsoft.com/en-us/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);
}

答案 1 :(得分:1)

基于@Tim代码并在此处提供了更有用的示例,这是我刚编写的用于与Restart Manager交互的类:

https://gist.github.com/falahati/34b23831733151460de1368c5fba8e93

这里是一个例子:

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

如果您想更具体一些,还可以使用以下代码来获取Explorer的主要过程:

Process.GetProcessesByName("explorer")[0]

然后,使用同一类通过Restart Manager重新启动它。无论如何,它比 Client client1 = clientViaApiKey(apikey); var api = new youtube.YoutubeApi(client1); 更好。