-
Notifications
You must be signed in to change notification settings - Fork 7.2k
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
Add 'Restart Windows Explorer' command, implemented using Restart Manager #39258
Conversation
…ed using the Restart Manager
@microsoft-github-policy-service agree |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
33b3253
to
dfe135a
Compare
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.
There was a problem hiding this 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., mockingNativeMethods
) 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()))) |
There was a problem hiding this comment.
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()
).
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.
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"); |
There was a problem hiding this comment.
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.
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.
src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.System/Helpers/ShellRestartHelper.cs
Outdated
Show resolved
Hide resolved
@@ -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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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."); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
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. |
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 |
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. |
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.
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. |
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" 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). |
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? |
I've researched this a little bit before. Task Manager's "Restart" just kills the process and starts it again. |
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
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 . |
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.
This comment has been minimized.
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Could you please merge main branch into this PR? Seems our pipeline has broken.@jiripolasek |
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
Thanks for your contribution! |
Thank you for your time and patience @moooyo! |
…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)  <!-- 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
Summary of the Pull Request
explorer
) is hardcodedexplorer
processes indiscriminatelyPR Checklist
Detailed Description of the Pull Request / Additional comments
Validation Steps Performed