Skip to content

Add 'Restart Windows Explorer' command, implemented using Restart Manager #39258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

jiripolasek
Copy link
Contributor

Summary of the Pull Request

  • Adds a new "Restart Windows Explorer" command to the "Windows System Commands" provider
  • Implemented using Restart Manager to allow restoring previously opened Explorer windows after restart
    • This depends on the "Restore previous folder windows at logon" option in File Explorer Options
    • An explicit timeout was added for terminating processes, since Restart Manager uses very long timeouts 😴
  • The shell process name (explorer) is hardcoded
  • The command attempts to terminate all explorer processes indiscriminately
  • Execution requires confirmation (if enabled in settings)

image

PR Checklist

Detailed Description of the Pull Request / Additional comments

Validation Steps Performed

@jiripolasek
Copy link
Contributor Author

@microsoft-github-policy-service agree

This comment has been minimized.

@zadjii-msft zadjii-msft added the Product-Command Palette Refers to the Command Palette utility label May 6, 2025

This comment has been minimized.

@jiripolasek jiripolasek force-pushed the feature/39213-restart-explorer-command branch from 33b3253 to dfe135a Compare May 8, 2025 12:34
Restricts process restarts to only affect the processes associated with the current session. This change prevents cross-session interference and supports multi-user scenarios more reliably.
@jiripolasek jiripolasek marked this pull request as ready for review May 12, 2025 15:10
@yeelam-gordon yeelam-gordon added this to the PowerToys 0.92 milestone May 16, 2025
@yeelam-gordon yeelam-gordon requested review from moooyo and Copilot May 16, 2025 06:50
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds a new “Restart Windows Explorer” command to the Windows System Commands provider, leveraging the Restart Manager API to gracefully terminate and relaunch explorer.exe.

  • Introduces localization entries for command name, description, confirmation
  • Implements ShellRestartHelper to orchestrate process shutdown/restart via Restart Manager
  • Updates command registry, icons, and native interop definitions

Reviewed Changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Properties/Resources.resx Added resource strings for the new restart command
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Helpers/ShellRestartHelper.cs New helper class to restart explorer.exe using Restart Manager
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Helpers/NativeMethods.cs Added P/Invoke signatures and structs for Restart Manager APIs
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Helpers/Icons.cs Added an icon entry for the shell restart command
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Helpers/Commands.cs Registered the Restart Windows Explorer command
.github/actions/spell-check/expect.txt Whitelisted “rstrtmgr” for spell-checker
Files not reviewed (1)
  • src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Properties/Resources.Designer.cs: Language not supported
Comments suppressed due to low confidence (2)

src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Helpers/ShellRestartHelper.cs:26

  • There are no unit tests covering ShellRestartHelper. Adding tests for the restart logic (e.g., mocking NativeMethods) would improve confidence in this complex behavior.
internal static async Task RestartAllInCurrentSession()

src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Properties/Resources.resx:427

  • [nitpick] The command name value is too generic. Consider using a more descriptive label like "Restart Explorer" to match the title and avoid UI ambiguity.
<value>Restart</value>

@@ -110,6 +111,13 @@ public static List<IListItem> GetSystemCommands(bool isUefi, bool hideEmptyRecyc
});
}

results.Add(new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_sys_RestartShell_name!, confirmCommands, Resources.Microsoft_plugin_sys_RestartShell_confirmation!, static () => Task.Run(static () => ShellRestartHelper.RestartAllInCurrentSession())))
Copy link
Preview

Copilot AI May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary use of Task.Run inside the command callback may complicate error propagation and cancellation. Consider passing the async method directly (e.g. static () => ShellRestartHelper.RestartAllInCurrentSession()).

Suggested change
results.Add(new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_sys_RestartShell_name!, confirmCommands, Resources.Microsoft_plugin_sys_RestartShell_confirmation!, static () => Task.Run(static () => ShellRestartHelper.RestartAllInCurrentSession())))
results.Add(new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_sys_RestartShell_name!, confirmCommands, Resources.Microsoft_plugin_sys_RestartShell_confirmation!, static () => ShellRestartHelper.RestartAllInCurrentSession()))

Copilot uses AI. Check for mistakes.

Comment on lines 36 to 41
await RestartProcessesInCurrentSessionAsync("explorer.exe");

// - Windows can automatically restart the shell if it detects that it has crashed. This can be disabled
// in registry (key AutoRestartShell).
// - Restart Manager is not guaranteed to restart all the processes it closes.
await EnsureProcessIsRunning("explorer.exe");
Copy link
Preview

Copilot AI May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The executable name "explorer.exe" is hard-coded in multiple places. Extract it to a private constant to avoid duplication and potential typos.

Suggested change
await RestartProcessesInCurrentSessionAsync("explorer.exe");
// - Windows can automatically restart the shell if it detects that it has crashed. This can be disabled
// in registry (key AutoRestartShell).
// - Restart Manager is not guaranteed to restart all the processes it closes.
await EnsureProcessIsRunning("explorer.exe");
await RestartProcessesInCurrentSessionAsync(ExplorerExecutableName);
// - Windows can automatically restart the shell if it detects that it has crashed. This can be disabled
// in registry (key AutoRestartShell).
// - Restart Manager is not guaranteed to restart all the processes it closes.
await EnsureProcessIsRunning(ExplorerExecutableName);

Copilot uses AI. Check for mistakes.

@@ -35,6 +35,36 @@ public static class NativeMethods

[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
public static extern uint SHEmptyRecycleBin(IntPtr hWnd, uint dwFlags);

[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
public static extern uint RmStartSession(out IntPtr pSessionHandle, uint dwSessionFlags, string strSessionKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to use LibraryImport. Can you try it out?

We are trying to make cmdpal to support native AOT.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some example in another extension. Try to search LibraryImport to see how to use it.

var result = await shutdownTask.WaitAsync(timeout);
if (result != 0)
{
ExtensionHost.LogMessage($"RmShutdown returned error {result}, performing force kill.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, now we have 2 behaviours here.
if killProcesses is acceptable, why we don't use it directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If RmShutdown isn't called, the process won't be restarted by RmRestart.

If the process doesn't exit after RmShutdown, we need to kill it quickly to keep the user experience smooth [^1]. Still, we must allow enough time for the process to save its state—otherwise, it can't restore its previous state. The balance is giving it just enough time to shut down cleanly without making the user wait too long.

@moooyo
Copy link
Contributor

moooyo commented Jun 11, 2025

I think we make the things more complicated. I've went through your PR, you mentined by default if user kill the explore, it will auto restart (unless user disabled this behaviour by registry).

So, how about just kill explore directly? It's simple and straightforward solution.

@jiripolasek
Copy link
Contributor Author

The only reason to use the Restart Manager is that it can restore previously opened Explorer windows. When we simply kill the process(es), those windows are not restored.

If we omit restoring the previous folder windows after a restart, we can indeed reduce the code to tskill explorer && start explorer. For me, restoring the previous state is a natural feature, as closing all the windows when restarting Explorer is just collateral damage.

@moooyo
Copy link
Contributor

moooyo commented Jun 11, 2025

The only reason to use the Restart Manager is that it can restore previously opened Explorer windows. When we simply kill the process(es), those windows are not restored.

If we omit restoring the previous folder windows after a restart, we can indeed reduce the code to tskill explorer && start explorer. For me, restoring the previous state is a natural feature, as closing all the windows when restarting Explorer is just collateral damage.

Ok, agree. Make sense.

But if restart failed, it will use tskill right?

So there are two behaviours base on user's env (restart manager work/not work).

I think this is so wired for user. Some one will notice they can successfully restore the window but another one will not.

I think it's better to use restart manager but remove the kill/start code path. If it failed, do nothing and show a toast to user.

Any insight?

@moooyo
Copy link
Contributor

moooyo commented Jun 11, 2025

The only reason to use the Restart Manager is that it can restore previously opened Explorer windows. When we simply kill the process(es), those windows are not restored.
If we omit restoring the previous folder windows after a restart, we can indeed reduce the code to tskill explorer && start explorer. For me, restoring the previous state is a natural feature, as closing all the windows when restarting Explorer is just collateral damage.

Ok, agree. Make sense.

But if restart failed, it will use tskill right?

So there are two behaviours base on user's env (restart manager work/not work).

I think this is so wired for user. Some one will notice they can successfully restore the window but another one will not.

I think it's better to use restart manager but remove the kill/start code path. If it failed, do nothing and show a toast to user.

Any insight?

Or we can split this command to 2 command. One is restart another one is kill.

Or add a setting to control the kill behaviour. Restore or not restore.

@jiripolasek
Copy link
Contributor Author

The only reason to use the Restart Manager is that it can restore previously opened Explorer windows. When we simply kill the process(es), those windows are not restored.
If we omit restoring the previous folder windows after a restart, we can indeed reduce the code to tskill explorer && start explorer. For me, restoring the previous state is a natural feature, as closing all the windows when restarting Explorer is just collateral damage.

Ok, agree. Make sense.

But if restart failed, it will use tskill right?

So there are two behaviours base on user's env (restart manager work/not work).

I think this is so wired for user. Some one will notice they can successfully restore the window but another one will not.

I think it's better to use restart manager but remove the kill/start code path. If it failed, do nothing and show a toast to user.

Any insight?

I think we should silently fall back to killing the processes.

As a user, I want to restart Windows Explorer. I don't care how it happens. If I get a toast saying it can't be done, the next thing I'll to do is kill it by another means.

If we care about maintaining 100% consistent behavior, then we should ditch Restart Manager and go with the kill-and-start approach. Using Restart Manager only gives Windows Explorer the option to restore previous folders, but we can’t guarantee that outcome since we don’t control it. In fact, the user can prevent Explorer from restoring folders via File Explorer Options.

Or we can split this command to 2 command. One is restart another one is kill.
Or add a setting to control the kill behaviour. Restore or not restore.

I can imagine an option formulated as "Attempt to restore previous folder windows after Windows Explorer restarts," which conveys that we will try, but might not succeed.

@jiripolasek
Copy link
Contributor Author

I was looking into better error handling and got an idea to replace Restart Manager entirely. It's just rough prototype, but for me it makes more sense: jiripolasek@c374af4

Any thoughts?

@moooyo
Copy link
Contributor

moooyo commented Jun 13, 2025

I was looking into better error handling and got an idea to replace Restart Manager entirely. It's just rough prototype, but for me it makes more sense: jiripolasek@c374af4

Any thoughts?

oh...

I guess if we send the end message to process, they may show a dialog to user to make them decide exit or save (same as shutdown the computer)?

Actually, I see in the task manager Windows Explorer have a special item "Restart"
image

I don't know the gap between restart manager and this ability. If we can use this ability I think it's the best choice (to be honest, I don't know anything about it).

@moooyo
Copy link
Contributor

moooyo commented Jun 13, 2025

Summarize my idea:

I think it should have a stable functionality. Both restart manager and tkill is acceptable for me. But mix it I think it's wired...

or anyone have any idea?

@jiripolasek
Copy link
Contributor Author

I don't know the gap between restart manager and this ability. If we can use this ability I think it's the best choice (to be honest, I don't know anything about it).

I've researched this a little bit before. Task Manager's "Restart" just kills the process and starts it again.

@moooyo
Copy link
Contributor

moooyo commented Jun 16, 2025

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jiripolasek
Copy link
Contributor Author

Hello @moooyo, how would you like to follow up with this?

I'd suggest we go with kill-and-start as we can both agree on that solution.

I don't think we should use only Restart Manager as the user experience is not good when Explorer is quirky and won't shutdown upon request from RM (and unfortunately that is not uncommon).

@moooyo
Copy link
Contributor

moooyo commented Jun 16, 2025

Hello @moooyo, how would you like to follow up with this?

I'd suggest we go with kill-and-start as we can both agree on that solution.

I don't think we should use only Restart Manager as the user experience is not good when Explorer is quirky and won't shutdown upon request from RM (and unfortunately that is not uncommon).

Agree.

And there is still one thing need to address. Could you please try to use LibraryImport instead of DllImport?

If any question or any problem, let me know I'm happy to help .

@jiripolasek
Copy link
Contributor Author

Without the Restart Manager, there’s no need for those native methods, so I’ll remove them.

…l/start instead

Trading the ability to reopen the previous folder in exchange for a simpler solution and more consistent behavior across Windows versions.

- Reverted addition of Restart Manager
- Replaced with `tskill` and `start` commands to restart Windows Explorer

This comment has been minimized.

@jiripolasek jiripolasek requested a review from moooyo June 16, 2025 03:39
@moooyo
Copy link
Contributor

moooyo commented Jun 16, 2025

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Contributor

@moooyo moooyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@moooyo
Copy link
Contributor

moooyo commented Jun 16, 2025

Could you please merge main branch into this PR? Seems our pipeline has broken.@jiripolasek

@moooyo
Copy link
Contributor

moooyo commented Jun 16, 2025

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@moooyo moooyo merged commit 74d92df into microsoft:main Jun 16, 2025
8 of 10 checks passed
@moooyo
Copy link
Contributor

moooyo commented Jun 16, 2025

Thanks for your contribution!

@jiripolasek
Copy link
Contributor Author

Thank you for your time and patience @moooyo!

yeelam-gordon pushed a commit that referenced this pull request Jun 20, 2025
…ager (#39258)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
- Adds a new **"Restart Windows Explorer"** command to the **"Windows
System Commands"** provider
- Implemented using **Restart Manager** to allow restoring previously
opened Explorer windows after restart
- This depends on the *"Restore previous folder windows at logon"*
option in File Explorer Options
- An explicit timeout was added for terminating processes, since Restart
Manager uses very long timeouts 😴
- The shell process name (`explorer`) is hardcoded  
- The command attempts to terminate all `explorer` processes
indiscriminately
- Execution requires confirmation (if enabled in settings)


![image](https://github.com/user-attachments/assets/a9a955d5-a52b-4a57-bcb1-85293362c17a)


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] **Closes:** #39213 
- [ ] **Communication:** I've discussed this with core contributors
already. If work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Good to Merge Product-Command Palette Refers to the Command Palette utility
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants