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