diff --git a/dnSpy/dnSpy/MainApp/AppWindow.cs b/dnSpy/dnSpy/MainApp/AppWindow.cs index 50883b5ef0..fd50778f01 100644 --- a/dnSpy/dnSpy/MainApp/AppWindow.cs +++ b/dnSpy/dnSpy/MainApp/AppWindow.cs @@ -143,7 +143,7 @@ public Window InitializeMainWindow() { #if DEBUG AddTitleInfo("Debug Build"); #endif - if (IsAdministrator()) + if (Constants.IsRunningAsAdministrator) AddTitleInfo(dnSpy_Resources.User_Administrator); wpfCommandService.Add(ControlConstants.GUID_MAINWINDOW, mainWindow); new SavedWindowStateRestorer(mainWindow, uiSettings.SavedWindowState, DefaultWindowLocation); @@ -154,11 +154,6 @@ public Window InitializeMainWindow() { return mainWindow; } - static bool IsAdministrator() { - using (var id = WindowsIdentity.GetCurrent()) - return new WindowsPrincipal(id).IsInRole(WindowsBuiltInRole.Administrator); - } - void IDsLoaderContentProvider.SetLoadingContent(object content) { Debug.Assert(stackedContent.Count == 0); stackedContent.AddChild(StackedContentChildImpl.GetOrCreate(content, content)); diff --git a/dnSpy/dnSpy/MainApp/Constants.cs b/dnSpy/dnSpy/MainApp/Constants.cs index c48b6de1e6..42a99c3e60 100644 --- a/dnSpy/dnSpy/MainApp/Constants.cs +++ b/dnSpy/dnSpy/MainApp/Constants.cs @@ -17,10 +17,19 @@ You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ +using System.Security.Principal; + namespace dnSpy.MainApp { static class Constants { public const string DnSpy = "dnSpy"; // Used in filenames so must only have valid filename chars public const string DnSpyFile = DnSpy; + + public static bool IsRunningAsAdministrator { get; } + + static Constants() { + using var id = WindowsIdentity.GetCurrent(); + IsRunningAsAdministrator = new WindowsPrincipal(id).IsInRole(WindowsBuiltInRole.Administrator); + } } } diff --git a/dnSpy/dnSpy/MainApp/RestartAsAdministratorCommand.cs b/dnSpy/dnSpy/MainApp/RestartAsAdministratorCommand.cs new file mode 100644 index 0000000000..913f8dbf4c --- /dev/null +++ b/dnSpy/dnSpy/MainApp/RestartAsAdministratorCommand.cs @@ -0,0 +1,61 @@ +/* + Copyright (C) 2024 ElektroKill + + This file is part of dnSpy + + dnSpy is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + dnSpy is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with dnSpy. If not, see . +*/ + +using System.ComponentModel; +using System.ComponentModel.Composition; +using System.Diagnostics; +using System.Reflection; +using System.Windows.Input; +using dnSpy.Contracts.App; +using dnSpy.Contracts.Menus; + +namespace dnSpy.MainApp { + [ExportMenuItem(OwnerGuid = MenuConstants.APP_MENU_FILE_GUID, Header = "res:RestartAsAdministratorCommand", Group = MenuConstants.GROUP_APP_MENU_FILE_EXIT, Order = 900000)] + sealed class RestartAsAdministratorCommand : MenuItemBase { + readonly IAppWindow appWindow; + + [ImportingConstructor] + public RestartAsAdministratorCommand(IAppWindow appWindow) => this.appWindow = appWindow; + + public override bool IsVisible(IMenuItemContext context) => !Constants.IsRunningAsAdministrator; + + public override void Execute(IMenuItemContext context) { + appWindow.MainWindowClosing += OnMainWindowClosing; + ((ICommand)ApplicationCommands.Close).Execute(context); + } + + void OnMainWindowClosing(object? sender, CancelEventArgs args) { + appWindow.MainWindowClosing -= OnMainWindowClosing; + // If a different handler canceled the close operation, don't restart. + if (args.Cancel) + return; + var location = Assembly.GetEntryAssembly()?.Location; + if (location is null) { + args.Cancel = true; + return; + } + try { + Process.Start(new ProcessStartInfo(location) { UseShellExecute = true, Verb = "runas" }); + } + catch { + args.Cancel = true; + } + } + } +} diff --git a/dnSpy/dnSpy/Properties/dnSpy.Resources.Designer.cs b/dnSpy/dnSpy/Properties/dnSpy.Resources.Designer.cs index 1a53d78bb7..ba59497ecd 100644 --- a/dnSpy/dnSpy/Properties/dnSpy.Resources.Designer.cs +++ b/dnSpy/dnSpy/Properties/dnSpy.Resources.Designer.cs @@ -3961,6 +3961,15 @@ public static string ResourcesFolder { } } + /// + /// Looks up a localized string similar to Restart as Administrator. + /// + public static string RestartAsAdministratorCommand { + get { + return ResourceManager.GetString("RestartAsAdministratorCommand", resourceCulture); + } + } + /// /// Looks up a localized string similar to Ctrl+S. /// diff --git a/dnSpy/dnSpy/Properties/dnSpy.Resources.resx b/dnSpy/dnSpy/Properties/dnSpy.Resources.resx index 472c982637..d4af0c7edd 100644 --- a/dnSpy/dnSpy/Properties/dnSpy.Resources.resx +++ b/dnSpy/dnSpy/Properties/dnSpy.Resources.resx @@ -504,6 +504,9 @@ Resources + + Restart as Administrator + Ctrl+S