diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetCommonStartDebuggingOptionsPage.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetCommonStartDebuggingOptionsPage.cs index 9f6f0a7ec7..4bc593adf3 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetCommonStartDebuggingOptionsPage.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetCommonStartDebuggingOptionsPage.cs @@ -26,6 +26,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.DotNet.CorDebug; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.MVVM; +using dnSpy.Contracts.Settings; using dnSpy.Debugger.DotNet.CorDebug.Properties; namespace dnSpy.Debugger.DotNet.CorDebug.Dialogs.DebugProgram { @@ -173,6 +174,25 @@ protected T InitializeDefault(T options, string breakKind) where T : CorDebug return options; } + protected static void SerializeCorDebugOptions(ISettingsSection section, CorDebugStartDebuggingOptions options) { + if (options.BreakKind is not null) + section.Attribute(nameof(options.BreakKind), options.BreakKind); + if (options.Filename is not null) + section.Attribute(nameof(options.Filename), options.Filename); + if (options.CommandLine is not null) + section.Attribute(nameof(options.CommandLine), options.CommandLine); + if (options.WorkingDirectory is not null) + section.Attribute(nameof(options.WorkingDirectory), options.WorkingDirectory); + // The environment isn't serialized, it always contains all of the current process' environment variables + } + + protected static void DeserializeCorDebugOptions(ISettingsSection section, CorDebugStartDebuggingOptions options) { + options.BreakKind = section.Attribute(nameof(options.BreakKind)) ?? options.BreakKind; + options.Filename = section.Attribute(nameof(options.Filename)); + options.CommandLine = section.Attribute(nameof(options.CommandLine)); + options.WorkingDirectory = section.Attribute(nameof(options.WorkingDirectory)); + } + protected T GetOptions(T options) where T : CorDebugStartDebuggingOptions { options.Filename = Filename; options.CommandLine = CommandLine; diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetFrameworkStartDebuggingOptionsPage.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetFrameworkStartDebuggingOptionsPage.cs index e104948d5a..be8e2d6726 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetFrameworkStartDebuggingOptionsPage.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetFrameworkStartDebuggingOptionsPage.cs @@ -29,6 +29,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.StartDebugging; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.MVVM; +using dnSpy.Contracts.Settings; using dnSpy.Debugger.DotNet.CorDebug.Properties; using dnSpy.Debugger.DotNet.CorDebug.Utilities; @@ -121,6 +122,22 @@ public override bool SupportsDebugEngine(Guid engineGuid, out double order) { return false; } + public override bool SerializeOptions(ISettingsSection section, StartDebuggingOptions options) { + if (options is not DotNetFrameworkStartDebuggingOptions dnfOptions) + return false; + SerializeCorDebugOptions(section, dnfOptions); + if (dnfOptions.DebuggeeVersion is not null) + section.Attribute(nameof(dnfOptions.DebuggeeVersion), dnfOptions.DebuggeeVersion); + return true; + } + + public override StartDebuggingOptions? DeserializeOptions(ISettingsSection section) { + var options = new DotNetFrameworkStartDebuggingOptions(); + DeserializeCorDebugOptions(section, options); + options.DebuggeeVersion = section.Attribute(nameof(options.DebuggeeVersion)); + return options; + } + protected override bool CalculateIsValid() => string.IsNullOrEmpty(Verify(nameof(Filename))); protected override string Verify(string columnName) { diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetStartDebuggingOptionsPage.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetStartDebuggingOptionsPage.cs index 58468b1604..92c5b6f3a1 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetStartDebuggingOptionsPage.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.CorDebug/Dialogs/DebugProgram/DotNetStartDebuggingOptionsPage.cs @@ -28,6 +28,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.StartDebugging; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.MVVM; +using dnSpy.Contracts.Settings; using dnSpy.Debugger.DotNet.CorDebug.Utilities; namespace dnSpy.Debugger.DotNet.CorDebug.Dialogs.DebugProgram { @@ -162,6 +163,29 @@ public override bool SupportsDebugEngine(Guid engineGuid, out double order) { return false; } + public override bool SerializeOptions(ISettingsSection section, StartDebuggingOptions options) { + if (options is not DotNetStartDebuggingOptions dncOptions) + return false; + SerializeCorDebugOptions(section, dncOptions); + section.Attribute(nameof(dncOptions.UseHost), dncOptions.UseHost); + if (dncOptions.Host is not null) + section.Attribute(nameof(dncOptions.Host), dncOptions.Host); + if (dncOptions.HostArguments is not null) + section.Attribute(nameof(dncOptions.HostArguments), dncOptions.HostArguments); + section.Attribute(nameof(dncOptions.ConnectionTimeout), dncOptions.ConnectionTimeout); + return true; + } + + public override StartDebuggingOptions? DeserializeOptions(ISettingsSection section) { + var options = new DotNetStartDebuggingOptions(); + DeserializeCorDebugOptions(section, options); + options.UseHost = section.Attribute(nameof(options.UseHost)) ?? options.UseHost; + options.Host = section.Attribute(nameof(options.Host)); + options.HostArguments = section.Attribute(nameof(options.HostArguments)); + options.ConnectionTimeout = section.Attribute(nameof(options.ConnectionTimeout)) ?? options.ConnectionTimeout; + return options; + } + protected override bool CalculateIsValid() => string.IsNullOrEmpty(Verify(nameof(HostFilename))) && string.IsNullOrEmpty(Verify(nameof(Filename))) && !ConnectionTimeout.HasError; diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoConnectStartDebuggingOptionsPage.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoConnectStartDebuggingOptionsPage.cs index 76a0603a4a..e2c1b584da 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoConnectStartDebuggingOptionsPage.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoConnectStartDebuggingOptionsPage.cs @@ -21,6 +21,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger; using dnSpy.Contracts.Debugger.DotNet.Mono; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; +using dnSpy.Contracts.Settings; using dnSpy.Debugger.DotNet.Mono.Properties; namespace dnSpy.Debugger.DotNet.Mono.Dialogs.DebugProgram { @@ -56,5 +57,18 @@ public override StartDebuggingOptionsInfo GetOptions() { var options = GetOptions(new MonoConnectStartDebuggingOptions()); return new StartDebuggingOptionsInfo(options, null, StartDebuggingOptionsInfoFlags.None); } + + public override bool SerializeOptions(ISettingsSection section, StartDebuggingOptions options) { + if (options is not MonoConnectStartDebuggingOptions connectOptions) + return false; + SerializeMonoConnectOptions(section, connectOptions); + return true; + } + + public override StartDebuggingOptions? DeserializeOptions(ISettingsSection section) { + var options = new MonoConnectStartDebuggingOptions(); + DeserializeMonoConnectOptions(section, options); + return options; + } } } diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoConnectStartDebuggingOptionsPageBase.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoConnectStartDebuggingOptionsPageBase.cs index 2b6ff818fe..807260bd77 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoConnectStartDebuggingOptionsPageBase.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoConnectStartDebuggingOptionsPageBase.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.DotNet.Mono; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.MVVM; +using dnSpy.Contracts.Settings; namespace dnSpy.Debugger.DotNet.Mono.Dialogs.DebugProgram { abstract class MonoConnectStartDebuggingOptionsPageBase : StartDebuggingOptionsPage, IDataErrorInfo { @@ -108,6 +109,24 @@ protected T GetOptions(T options) where T : MonoConnectStartDebuggingOptionsB return options; } + protected static void SerializeMonoConnectOptions(ISettingsSection section, MonoConnectStartDebuggingOptionsBase options) { + if (options.BreakKind is not null) + section.Attribute(nameof(options.BreakKind), options.BreakKind); + if (options.Address is not null) + section.Attribute(nameof(options.Address), options.Address); + section.Attribute(nameof(options.Port), options.Port); + section.Attribute(nameof(options.ConnectionTimeout), options.ConnectionTimeout); + section.Attribute(nameof(options.ProcessIsSuspended), options.ProcessIsSuspended); + } + + protected static void DeserializeMonoConnectOptions(ISettingsSection section, MonoConnectStartDebuggingOptionsBase options) { + options.BreakKind = section.Attribute(nameof(options.BreakKind)) ?? options.BreakKind; + options.Address = section.Attribute(nameof(options.Address)); + options.Port = section.Attribute(nameof(options.Port)) ?? options.Port; + options.ConnectionTimeout = section.Attribute(nameof(options.ConnectionTimeout)) ?? options.ConnectionTimeout; + options.ProcessIsSuspended = section.Attribute(nameof(options.ProcessIsSuspended)) ?? options.ProcessIsSuspended; + } + string IDataErrorInfo.Error => throw new NotImplementedException(); string IDataErrorInfo.this[string columnName] => Verify(columnName); diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoStartDebuggingOptionsPage.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoStartDebuggingOptionsPage.cs index 36bb5ecadb..1394ec8dd7 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoStartDebuggingOptionsPage.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoStartDebuggingOptionsPage.cs @@ -26,6 +26,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.StartDebugging; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.MVVM; +using dnSpy.Contracts.Settings; namespace dnSpy.Debugger.DotNet.Mono.Dialogs.DebugProgram { sealed class MonoStartDebuggingOptionsPage : MonoStartDebuggingOptionsPageBase { @@ -126,6 +127,24 @@ public override bool SupportsDebugEngine(Guid engineGuid, out double order) { return false; } + public override bool SerializeOptions(ISettingsSection section, StartDebuggingOptions options) { + if (options is not MonoStartDebuggingOptions msdOptions) + return false; + SerializeMonoOptions(section, msdOptions); + if (msdOptions.MonoExePath is not null) + section.Attribute(nameof(msdOptions.MonoExePath), msdOptions.MonoExePath); + section.Attribute(nameof(msdOptions.MonoExeOptions), msdOptions.MonoExeOptions); + return true; + } + + public override StartDebuggingOptions? DeserializeOptions(ISettingsSection section) { + var options = new MonoStartDebuggingOptions(); + DeserializeMonoOptions(section, options); + options.MonoExePath = section.Attribute(nameof(options.MonoExePath)); + options.MonoExeOptions = section.Attribute(nameof(options.MonoExeOptions)) ?? options.MonoExeOptions; + return options; + } + protected override bool CalculateIsValidCore() => string.IsNullOrEmpty(Verify(nameof(MonoExePath))); protected override string VerifyCore(string columnName) { diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoStartDebuggingOptionsPageBase.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoStartDebuggingOptionsPageBase.cs index 0168f536e1..80d2590cef 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoStartDebuggingOptionsPageBase.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/MonoStartDebuggingOptionsPageBase.cs @@ -26,6 +26,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.DotNet.Mono; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.MVVM; +using dnSpy.Contracts.Settings; using dnSpy.Debugger.DotNet.Mono.Properties; namespace dnSpy.Debugger.DotNet.Mono.Dialogs.DebugProgram { @@ -194,6 +195,29 @@ protected void GetOptions(MonoStartDebuggingOptionsBase options) { options.BreakKind = FilterBreakKind(BreakKind); } + protected static void SerializeMonoOptions(ISettingsSection section, MonoStartDebuggingOptionsBase options) { + if (options.BreakKind is not null) + section.Attribute(nameof(options.BreakKind), options.BreakKind); + if (options.Filename is not null) + section.Attribute(nameof(options.Filename), options.Filename); + if (options.CommandLine is not null) + section.Attribute(nameof(options.CommandLine), options.CommandLine); + if (options.WorkingDirectory is not null) + section.Attribute(nameof(options.WorkingDirectory), options.WorkingDirectory); + section.Attribute(nameof(options.ConnectionPort), options.ConnectionPort); + section.Attribute(nameof(options.ConnectionTimeout), options.ConnectionTimeout); + // The environment isn't serialized, it always contains all of the current process' environment variables + } + + protected static void DeserializeMonoOptions(ISettingsSection section, MonoStartDebuggingOptionsBase options) { + options.BreakKind = section.Attribute(nameof(options.BreakKind)) ?? options.BreakKind; + options.Filename = section.Attribute(nameof(options.Filename)); + options.CommandLine = section.Attribute(nameof(options.CommandLine)); + options.WorkingDirectory = section.Attribute(nameof(options.WorkingDirectory)); + options.ConnectionPort = section.Attribute(nameof(options.ConnectionPort)) ?? options.ConnectionPort; + options.ConnectionTimeout = section.Attribute(nameof(options.ConnectionTimeout)) ?? options.ConnectionTimeout; + } + string IDataErrorInfo.Error => throw new NotImplementedException(); string IDataErrorInfo.this[string columnName] => Verify(columnName); diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/UnityConnectStartDebuggingOptionsPage.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/UnityConnectStartDebuggingOptionsPage.cs index f3fcf3a4fa..73b8347410 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/UnityConnectStartDebuggingOptionsPage.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/UnityConnectStartDebuggingOptionsPage.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.DotNet.Mono; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.MVVM; +using dnSpy.Contracts.Settings; using dnSpy.Debugger.DotNet.Mono.Properties; namespace dnSpy.Debugger.DotNet.Mono.Dialogs.DebugProgram { @@ -68,5 +69,18 @@ public override StartDebuggingOptionsInfo GetOptions() { var options = GetOptions(new UnityConnectStartDebuggingOptions()); return new StartDebuggingOptionsInfo(options, null, StartDebuggingOptionsInfoFlags.None); } + + public override bool SerializeOptions(ISettingsSection section, StartDebuggingOptions options) { + if (options is not UnityConnectStartDebuggingOptions connectOptions) + return false; + SerializeMonoConnectOptions(section, connectOptions); + return true; + } + + public override StartDebuggingOptions? DeserializeOptions(ISettingsSection section) { + var options = new UnityConnectStartDebuggingOptions { Port = DEFAULT_PORT }; + DeserializeMonoConnectOptions(section, options); + return options; + } } } diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/UnityStartDebuggingOptionsPage.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/UnityStartDebuggingOptionsPage.cs index d2087b862e..1fe05ef965 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/UnityStartDebuggingOptionsPage.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Dialogs/DebugProgram/UnityStartDebuggingOptionsPage.cs @@ -26,6 +26,7 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.StartDebugging; using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.MVVM; +using dnSpy.Contracts.Settings; namespace dnSpy.Debugger.DotNet.Mono.Dialogs.DebugProgram { sealed class UnityStartDebuggingOptionsPage : MonoStartDebuggingOptionsPageBase { @@ -104,6 +105,19 @@ public override bool SupportsDebugEngine(Guid engineGuid, out double order) { return false; } + public override bool SerializeOptions(ISettingsSection section, StartDebuggingOptions options) { + if (options is not UnityStartDebuggingOptions usdOptions) + return false; + SerializeMonoOptions(section, usdOptions); + return true; + } + + public override StartDebuggingOptions? DeserializeOptions(ISettingsSection section) { + var options = new UnityStartDebuggingOptions(); + DeserializeMonoOptions(section, options); + return options; + } + protected override bool CalculateIsValidCore() => true; protected override string VerifyCore(string columnName) => string.Empty; } diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger/DbgUI/StartDebuggingOptionsMru.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger/DbgUI/StartDebuggingOptionsMru.cs index f49b93f69a..055e22d771 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger/DbgUI/StartDebuggingOptionsMru.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger/DbgUI/StartDebuggingOptionsMru.cs @@ -79,6 +79,12 @@ public void Add(string filename, StartDebuggingOptions options, Guid pageGuid) { return (info.Options, info.PageGuid); } + public void SetLastOptions(StartDebuggingOptions options, Guid pageGuid) { + if (options is null) + throw new ArgumentNullException(nameof(options)); + lastOptions = ((StartDebuggingOptions)options.Clone(), pageGuid); + } + public (StartDebuggingOptions options, Guid pageGuid)? TryGetLastOptions() => lastOptions; } } diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger/DbgUI/StartDebuggingOptionsProvider.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger/DbgUI/StartDebuggingOptionsProvider.cs index 9a051710db..b79e66cf08 100644 --- a/Extensions/dnSpy.Debugger/dnSpy.Debugger/DbgUI/StartDebuggingOptionsProvider.cs +++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger/DbgUI/StartDebuggingOptionsProvider.cs @@ -32,23 +32,31 @@ You should have received a copy of the GNU General Public License using dnSpy.Contracts.Debugger.StartDebugging.Dialog; using dnSpy.Contracts.Documents.Tabs; using dnSpy.Contracts.Documents.TreeView; +using dnSpy.Contracts.Settings; using dnSpy.Debugger.Dialogs.DebugProgram; using dnSpy.Debugger.Properties; namespace dnSpy.Debugger.DbgUI { [Export(typeof(StartDebuggingOptionsProvider))] sealed class StartDebuggingOptionsProvider { + static readonly Guid SETTINGS_GUID = new Guid("1D06F2C9-BC3C-4D44-93B3-729F939F3F97"); + const string PageGuidAttr = "PageGuid"; + const string OptionsSectionName = "Options"; + readonly IAppWindow appWindow; readonly IDocumentTabService documentTabService; + readonly ISettingsService settingsService; readonly Lazy[] startDebuggingOptionsPageProviders; readonly Lazy dbgProcessStarterService; readonly Lazy[] genericDebugEngineGuidProviders; readonly StartDebuggingOptionsMru mru; + bool mruLoaded; [ImportingConstructor] - StartDebuggingOptionsProvider(IAppWindow appWindow, IDocumentTabService documentTabService, Lazy dbgProcessStarterService, [ImportMany] IEnumerable> startDebuggingOptionsPageProviders, [ImportMany] IEnumerable> genericDebugEngineGuidProviders) { + StartDebuggingOptionsProvider(IAppWindow appWindow, IDocumentTabService documentTabService, ISettingsService settingsService, Lazy dbgProcessStarterService, [ImportMany] IEnumerable> startDebuggingOptionsPageProviders, [ImportMany] IEnumerable> genericDebugEngineGuidProviders) { this.appWindow = appWindow; this.documentTabService = documentTabService; + this.settingsService = settingsService; this.dbgProcessStarterService = dbgProcessStarterService; this.startDebuggingOptionsPageProviders = startDebuggingOptionsPageProviders.ToArray(); this.genericDebugEngineGuidProviders = genericDebugEngineGuidProviders.OrderBy(a => a.Metadata.Order).ToArray(); @@ -85,6 +93,11 @@ string GetCurrentFilename() { if (pages.Length == 0) return default; + if (!mruLoaded) { + mruLoaded = true; + LoadLastOptions(pages); + } + var oldOptions = mru.TryGetOptions(filename); var lastOptions = mru.TryGetLastOptions(); foreach (var page in pages) { @@ -130,9 +143,36 @@ string GetCurrentFilename() { } mru.Add(info.Filename!, info.Options, vm.SelectedPageGuid); + SaveLastOptions(pages, info.Options, vm.SelectedPageGuid); return (info.Options, info.Flags); } + void LoadLastOptions(StartDebuggingOptionsPage[] pages) { + var section = settingsService.GetOrCreateSection(SETTINGS_GUID); + var pageGuid = section.Attribute(PageGuidAttr); + if (pageGuid is null) + return; + var optionsSection = section.TryGetSection(OptionsSectionName); + if (optionsSection is null) + return; + // The page could be missing, eg. if its extension got uninstalled or disabled + var page = pages.FirstOrDefault(a => a.Guid == pageGuid.Value); + var options = page?.DeserializeOptions(optionsSection); + if (options is null) + return; + mru.SetLastOptions(options, pageGuid.Value); + } + + void SaveLastOptions(StartDebuggingOptionsPage[] pages, StartDebuggingOptions options, Guid pageGuid) { + var page = pages.FirstOrDefault(a => a.Guid == pageGuid); + if (page is null) + return; + var section = settingsService.RecreateSection(SETTINGS_GUID); + section.Attribute(PageGuidAttr, pageGuid); + if (!page.SerializeOptions(section.CreateSection(OptionsSectionName), options)) + settingsService.RemoveSection(SETTINGS_GUID); + } + static bool? IsCompatibleWithCurrentArchitecture(string fileName) { int? bitness = null; try { diff --git a/dnSpy/dnSpy.Contracts.Debugger/StartDebugging/Dialog/StartDebuggingOptionsPage.cs b/dnSpy/dnSpy.Contracts.Debugger/StartDebugging/Dialog/StartDebuggingOptionsPage.cs index 011509650b..43974af671 100644 --- a/dnSpy/dnSpy.Contracts.Debugger/StartDebugging/Dialog/StartDebuggingOptionsPage.cs +++ b/dnSpy/dnSpy.Contracts.Debugger/StartDebugging/Dialog/StartDebuggingOptionsPage.cs @@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License using System; using System.ComponentModel; +using dnSpy.Contracts.Settings; namespace dnSpy.Contracts.Debugger.StartDebugging.Dialog { /// @@ -100,6 +101,24 @@ public abstract class StartDebuggingOptionsPage : INotifyPropertyChanged { /// Called when the dialog box gets closed /// public virtual void OnClose() { } + + /// + /// Serializes to so they can be + /// restored after dnSpy is restarted. Returns false if the options couldn't be serialized, + /// eg. it's an unsupported options type. The default implementation returns false. + /// + /// Destination section + /// Options created by this page, see + /// + public virtual bool SerializeOptions(ISettingsSection section, StartDebuggingOptions options) => false; + + /// + /// Deserializes options that were serialized by + /// or returns null if they couldn't be deserialized. The default implementation returns null. + /// + /// Section + /// + public virtual StartDebuggingOptions? DeserializeOptions(ISettingsSection section) => null; } ///