1using System; 2using System.IO; 3using System.Threading; 4using System.Windows.Forms; 5using WindowCapture.App; 6using WindowCapture.Helpers; 7using WindowCapture.Models; 8using WindowCapture.UI; 9 10namespace WindowCapture 11{ 12 static class Program 13 { 14 private static Mutex singleInstanceMutex; 15 16 [STAThread] 17 static void Main(string[] args) 18 { 19 // Enable DPI awareness for correct capture at non-100% scaling 20 try { Native.WinApi.SetProcessDpiAwareness(Native.WinApi.PROCESS_PER_MONITOR_DPI_AWARE); } 21 catch { try { Native.WinApi.SetProcessDPIAware(); } catch { } } 22 23 // Enable modern TLS. .NET Framework defaults to SSL3|TLS1.0, which Google's Gemini API 24 // and most HTTPS endpoints now reject ("Could not create SSL/TLS secure channel"). 25 // Numeric casts (Tls12=3072, Tls11=768) compile even if the 4.0 enum lacks these members. 26 try { System.Net.ServicePointManager.SecurityProtocol |= (System.Net.SecurityProtocolType)3072 | (System.Net.SecurityProtocolType)768; } 27 catch { } 28 29 Application.EnableVisualStyles(); 30 Application.SetCompatibleTextRenderingDefault(false); 31 32 // Load settings 33 Settings.Load(); 34 KeyBindings.Load(); 35 36 37 // If a real file path was passed (not a --mode flag), open it in viewer mode. 38 if (args != null && args.Length > 0 && File.Exists(args[0])) 39 { 40 string ext = System.IO.Path.GetExtension(args[0]).ToLowerInvariant(); 41 if (MediaTypes.IsAudio(ext)) 42 Application.Run(new AudioPlayerForm(args[0])); 43 else 44 Application.Run(new EditorForm(args[0])); 45 return; 46 } 47 48 // Otherwise route to the selected app mode (no flag => the unified MediaCore app: 49 // one tray icon, modules toggled live from its right-click menu). 50 AppMode mode = AppModes.Parse(args); 51 52 // Single instance PER MODE: different apps coexist (each installs only the hooks it 53 // needs), but a second launch of the SAME app signals the running one to surface 54 // (windowed apps + launcher) and then exits — no doubled hooks within one app. 55 bool createdNew; 56 singleInstanceMutex = new Mutex(true, AppModes.MutexName(mode), out createdNew); 57 if (!createdNew) 58 { 59 try 60 { 61 var ev = System.Threading.EventWaitHandle.OpenExisting(AppModes.ShowEventName(mode)); 62 ev.Set(); ev.Close(); 63 } 64 catch { /* tray-only apps have no show-event; just exit */ } 65 return; 66 } 67 68 try 69 { 70 switch (mode) 71 { 72 case AppMode.Screenshot: Application.Run(new TrayApp(AppMode.Screenshot)); break; 73 case AppMode.TextAssist: Application.Run(new TrayApp(AppMode.TextAssist)); break; 74 case AppMode.Clipboard: Application.Run(new TrayApp(AppMode.Clipboard)); break; 75 case AppMode.Soundpad: Application.Run(new FormHostApp(AppMode.Soundpad, new SoundpadForm())); break; 76 case AppMode.Search: SearchForm.BeginMftScan(); Application.Run(new FormHostApp(AppMode.Search, new SearchForm())); break; 77 case AppMode.Launcher: Application.Run(new LauncherApp()); break; // optional radial hub (--launcher) 78 default: Application.Run(new TrayApp(AppMode.MediaCore)); break; // unified app (no flag) 79 } 80 } 81 finally 82 { 83 singleInstanceMutex.ReleaseMutex(); 84 singleInstanceMutex.Dispose(); 85 } 86 } 87 } 88}