| | | 1 | | using System; |
| | | 2 | | using Microsoft.Extensions.DependencyInjection; |
| | | 3 | | using SwitchBlade.Contracts; |
| | | 4 | | using SwitchBlade.Core; |
| | | 5 | | using SwitchBlade.ViewModels; |
| | | 6 | | |
| | | 7 | | namespace SwitchBlade.Services |
| | | 8 | | { |
| | | 9 | | /// <summary> |
| | | 10 | | /// Composition root for dependency injection configuration. |
| | | 11 | | /// All services are registered via factories for 100% constructor-driven initialization. |
| | | 12 | | /// </summary> |
| | | 13 | | public static class ServiceConfiguration |
| | | 14 | | { |
| | | 15 | | /// <summary> |
| | | 16 | | /// Configures and returns the service provider with all registered services. |
| | | 17 | | /// </summary> |
| | | 18 | | public static IServiceProvider ConfigureServices() |
| | 1 | 19 | | { |
| | 1 | 20 | | var services = new ServiceCollection(); |
| | 1 | 21 | | ConfigureServices(services); |
| | 1 | 22 | | return services.BuildServiceProvider(); |
| | 1 | 23 | | } |
| | | 24 | | |
| | | 25 | | /// <summary> |
| | | 26 | | /// Configures the service collection with all application services. |
| | | 27 | | /// </summary> |
| | | 28 | | public static void ConfigureServices(IServiceCollection services) |
| | 3 | 29 | | { |
| | | 30 | | |
| | | 31 | | // System Abstractions (v1.9.11 coverage improvements) |
| | 3 | 32 | | services.AddSingleton<ISystemProcessProvider, SystemProcessProvider>(); |
| | 3 | 33 | | services.AddSingleton<IProcessFactory, ProcessFactory>(); |
| | 3 | 34 | | services.AddSingleton<IFileSystem, FileSystemWrapper>(); |
| | 3 | 35 | | services.AddSingleton<IRegistryService, RegistryServiceWrapper>(); |
| | 3 | 36 | | services.AddSingleton<INativeInteropWrapper, NativeInteropWrapper>(); |
| | 3 | 37 | | services.AddSingleton<IWindowInterop, WindowInterop>(); |
| | | 38 | | |
| | | 39 | | // Core Services |
| | 3 | 40 | | services.AddSingleton<SettingsService>(sp => |
| | 1 | 41 | | { |
| | 1 | 42 | | var registryService = sp.GetRequiredService<IRegistryService>(); |
| | 1 | 43 | | var logger = sp.GetRequiredService<ILogger>(); |
| | 1 | 44 | | return new SettingsService( |
| | 1 | 45 | | new RegistrySettingsStorage(@"Software\SwitchBlade", registryService), |
| | 1 | 46 | | new WindowsStartupManager(registryService), |
| | 1 | 47 | | logger); |
| | 4 | 48 | | }); |
| | 4 | 49 | | services.AddSingleton<ISettingsService>(sp => sp.GetRequiredService<SettingsService>()); |
| | 3 | 50 | | services.AddSingleton<ThemeService>(); |
| | 3 | 51 | | services.AddSingleton<IDispatcherService, WpfDispatcherService>(); |
| | 4 | 52 | | services.AddSingleton<IIconService>(sp => new IconService(sp.GetRequiredService<ISettingsService>(), sp.GetR |
| | 3 | 53 | | services.AddSingleton<IIconExtractor, IconExtractor>(); |
| | | 54 | | |
| | | 55 | | // Logger & Plugin Context |
| | 3 | 56 | | services.AddSingleton<ILogger>(Logger.Instance); |
| | 4 | 57 | | services.AddSingleton<IPluginContext>(sp => new PluginContext( |
| | 4 | 58 | | sp.GetRequiredService<ILogger>(), |
| | 4 | 59 | | sp.GetRequiredService<IWindowInterop>(), |
| | 4 | 60 | | sp.GetRequiredService<IRegistryService>())); |
| | 3 | 61 | | services.AddSingleton<IWorkstationService, WorkstationService>(); |
| | | 62 | | |
| | | 63 | | // New Services (v1.6.4) |
| | 3 | 64 | | services.AddSingleton<IPluginLoader>(sp => |
| | 4 | 65 | | new PluginLoader(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins"), sp.GetRequire |
| | | 66 | | |
| | 4 | 67 | | services.AddSingleton<WindowFinder>(sp => new WindowFinder( |
| | 4 | 68 | | sp.GetRequiredService<ISettingsService>(), |
| | 4 | 69 | | sp.GetRequiredService<IWindowInterop>())); |
| | | 70 | | |
| | 3 | 71 | | services.AddSingleton<INavigationService, NavigationService>(); |
| | 4 | 72 | | services.AddSingleton<IPluginService>(sp => new PluginService( |
| | 4 | 73 | | sp.GetRequiredService<IPluginContext>(), |
| | 4 | 74 | | sp.GetRequiredService<ISettingsService>(), |
| | 4 | 75 | | sp.GetRequiredService<IRegistryService>(), |
| | 4 | 76 | | sp.GetRequiredService<ILogger>(), |
| | 4 | 77 | | sp.GetRequiredService<IPluginLoader>(), |
| | 4 | 78 | | sp.GetRequiredService<WindowFinder>())); |
| | | 79 | | |
| | | 80 | | // Matching Algorithm |
| | 3 | 81 | | services.AddSingleton<IMatcher, FuzzyMatcherAdapter>(); |
| | | 82 | | |
| | | 83 | | // Window Search Service (with LRU cache) |
| | 3 | 84 | | services.AddSingleton<IWindowSearchService>(sp => |
| | 1 | 85 | | { |
| | 1 | 86 | | var settings = sp.GetRequiredService<ISettingsService>(); |
| | 1 | 87 | | int cacheSize = settings.Settings.RegexCacheSize; |
| | 1 | 88 | | var matcher = sp.GetRequiredService<IMatcher>(); |
| | 1 | 89 | | return new WindowSearchService(new LruRegexCache(cacheSize), matcher); |
| | 4 | 90 | | }); |
| | | 91 | | |
| | 3 | 92 | | services.AddSingleton<INumberShortcutService, NumberShortcutService>(); |
| | | 93 | | |
| | | 94 | | // UIA Worker Client (out-of-process UIA scanning) |
| | 3 | 95 | | services.AddSingleton<IUiaWorkerClient>(sp => |
| | 3 | 96 | | { |
| | 3 | 97 | | var logger = sp.GetRequiredService<ILogger>(); |
| | 3 | 98 | | var settings = sp.GetRequiredService<ISettingsService>(); |
| | 3 | 99 | | var processFactory = sp.GetRequiredService<IProcessFactory>(); |
| | 3 | 100 | | var fileSystem = sp.GetRequiredService<IFileSystem>(); |
| | 3 | 101 | | var timeoutSeconds = settings.Settings.UiaWorkerTimeoutSeconds; |
| | 3 | 102 | | var timeout = TimeSpan.FromSeconds(timeoutSeconds > 0 ? timeoutSeconds : 60); |
| | 3 | 103 | | return new UiaWorkerClient(logger, timeout, processFactory, fileSystem); |
| | 6 | 104 | | }); |
| | | 105 | | |
| | | 106 | | // Window Orchestration Service (replaces manual provider coordination) |
| | 3 | 107 | | services.AddSingleton<IWindowReconciler>(sp => |
| | 4 | 108 | | new WindowReconciler(sp.GetRequiredService<IIconService>(), sp.GetRequiredService<ILogger>())); |
| | | 109 | | |
| | 3 | 110 | | services.AddSingleton<IWindowOrchestrationService>(sp => |
| | 1 | 111 | | { |
| | 1 | 112 | | var pluginService = sp.GetRequiredService<IPluginService>(); |
| | 1 | 113 | | var reconciler = sp.GetRequiredService<IWindowReconciler>(); |
| | 1 | 114 | | var uiaWorkerClient = sp.GetRequiredService<IUiaWorkerClient>(); |
| | 1 | 115 | | var nativeInterop = sp.GetRequiredService<INativeInteropWrapper>(); |
| | 1 | 116 | | var logger = sp.GetRequiredService<ILogger>(); |
| | 1 | 117 | | var settingsService = sp.GetRequiredService<ISettingsService>(); |
| | 3 | 118 | | |
| | 1 | 119 | | return new WindowOrchestrationService( |
| | 1 | 120 | | pluginService.Providers, |
| | 1 | 121 | | reconciler, |
| | 1 | 122 | | uiaWorkerClient, |
| | 1 | 123 | | nativeInterop, |
| | 1 | 124 | | new InProcessProviderRunner(logger), |
| | 1 | 125 | | new UiaProviderRunner(uiaWorkerClient, logger), |
| | 1 | 126 | | logger); |
| | 4 | 127 | | }); |
| | | 128 | | |
| | | 129 | | // ViewModels |
| | 4 | 130 | | services.AddTransient<MainViewModel>(sp => new MainViewModel( |
| | 4 | 131 | | sp.GetRequiredService<IWindowOrchestrationService>(), |
| | 4 | 132 | | sp.GetRequiredService<IWindowSearchService>(), |
| | 4 | 133 | | sp.GetRequiredService<INavigationService>(), |
| | 4 | 134 | | sp.GetRequiredService<ISettingsService>(), |
| | 4 | 135 | | sp.GetRequiredService<IDispatcherService>() |
| | 4 | 136 | | )); |
| | | 137 | | |
| | 3 | 138 | | services.AddSingleton<IUIService, WpfUIService>(); |
| | 3 | 139 | | services.AddSingleton<MainWindow>(); |
| | 4 | 140 | | services.AddTransient<SettingsViewModel>(sp => new SettingsViewModel( |
| | 4 | 141 | | sp.GetRequiredService<ISettingsService>(), |
| | 4 | 142 | | sp.GetRequiredService<ThemeService>(), |
| | 4 | 143 | | sp.GetRequiredService<IPluginService>(), |
| | 4 | 144 | | sp.GetRequiredService<IUIService>() |
| | 4 | 145 | | )); |
| | | 146 | | |
| | | 147 | | // Diagnostics (Investigation) |
| | 3 | 148 | | services.AddSingleton<MemoryDiagnosticsService>(); |
| | 3 | 149 | | } |
| | | 150 | | } |
| | | 151 | | } |