static void Main(string[] initialArgs) { string cmd = initialArgs[0]; ArrayList args = new ArrayList(initialArgs); args.RemoveAt(0); string argstr = QuoteArguments.Quote(args); // System.Console.Error.WriteLine(argstr); // XXX var p = Process.Start( new ProcessStartInfo(cmd, argstr) { UseShellExecute = false } ); p.WaitForExit(); Environment.Exit(p.ExitCode); }
static void Main(string[] args) { // Read config file List <FileType> types = new List <FileType>(); string json = File.ReadAllText(Path.Combine(BaseDirectory, "config.json")); JObject config = JObject.Parse(json); foreach (JProperty prop in config.Value <JObject>("types").Properties()) { FileType type = prop.Value.ToObject <FileType>(); type.Extension = prop.Name; type.Icon = ResolveIcon(type.Icon ?? type.Extension); type.Open = ResolveCommand(config, type.Open); type.Menu = type.Menu.ToDictionary(x => x.Key, x => ResolveCommand(config, x.Value)); types.Add(type); } // Open registry // HKEY_CLASSES_ROOT by default writes to HKEY_LOCAL_MACHINE\Software\Classes which requires admin; // using HKEY_CURRENT_USER's instead to avoid requiring elevation and also to keep changes user-specific using (var currentUserKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64)) // Prevent System32 being rewritten to SysWow64 using (var softwareKey = currentUserKey.OpenSubKey("Software", true)) using (var classesKey = softwareKey.OpenSubKey("Classes", true)) { // Nuke existing file types foreach (string keyName in classesKey.GetSubKeyNames()) { if (keyName.StartsWith($"{RegistryName}.")) { classesKey.DeleteSubKeyTree(keyName); } } // Add new file types foreach (FileType type in types) { using (var key = classesKey.CreateSubKey(GetTypeId(type))) { key.SetValue(null, type.Name); using (var iconKey = key.CreateSubKey("DefaultIcon")) { iconKey.SetValue(null, type.Icon); } using (var shellKey = key.CreateSubKey("shell")) { using (var openKey = shellKey.CreateSubKey("open")) using (var openCommandKey = openKey.CreateSubKey("command")) { openCommandKey.SetValue(null, $"{QuoteArguments.Quote(new[] { ProxyExePath })} {type.Open}"); // Open through proxy in order to appear as one app } foreach (var menuItem in type.Menu) { string menuItemId = Regex.Replace(menuItem.Key, "&(?!&)", ""); using (var menuItemKey = shellKey.CreateSubKey(menuItemId)) using (var menuItemCommandKey = menuItemKey.CreateSubKey("command")) { menuItemKey.SetValue(null, menuItem.Key); menuItemCommandKey.SetValue(null, menuItem.Value); } } } } } // Register as an option in Default Apps using (var registeredAppsKey = softwareKey.OpenSubKey("RegisteredApplications", true)) using (var appKey = softwareKey.CreateSubKey(RegistryName)) using (var capabilitiesKey = appKey.CreateSubKey("Capabilities")) { capabilitiesKey.SetValue("ApplicationDescription", ProductName); capabilitiesKey.DeleteSubKeyTree("FileAssociations", false); using (var fileAssocKey = capabilitiesKey.CreateSubKey("FileAssociations")) { foreach (FileType type in types) { fileAssocKey.SetValue($".{type.Extension}", GetTypeId(type)); foreach (string alias in type.Aliases) { fileAssocKey.SetValue($".{alias}", GetTypeId(type)); } } } registeredAppsKey.SetValue(RegistryName, $@"Software\{RegistryName}\Capabilities"); } } Native.UpdateShellAssociations(); Console.WriteLine("Registered file types."); // Create test files var extensions = types.SelectMany(t => new[] { t.Extension }.Concat(t.Aliases)).OrderBy(x => x).ToList(); string testDir = Path.Combine(BaseDirectory, "test"); Directory.CreateDirectory(testDir); foreach (string file in Directory.EnumerateFiles(testDir, "test.*")) { if (!extensions.Contains(Path.GetExtension(file).Substring(1))) { File.Delete(file); } } foreach (string ext in extensions) { File.Create(Path.Combine(testDir, "test." + ext)); } // Show settings UI if any not already set string[] GetUnset() => extensions.Where(x => !string.Equals(Native.GetAssociatedProgram(x), ProxyExePath, StringComparison.OrdinalIgnoreCase)).ToArray(); var unset = GetUnset(); if (unset.Length > 0) { if (unset.Length < extensions.Count) { Console.WriteLine("\nThe following extensions are not currently associated with the custom types:"); foreach (string ext in unset) { Console.WriteLine(" " + ext); } Console.WriteLine(); } if (Environment.OSVersion.Version.Major < 10) { Console.WriteLine("Opening Default Programs. Select all and save."); } else { Console.WriteLine($"Opening Default Apps. Choose \"Set defaults by app\" and find \"{ProductName}\"."); } Native.ShowDefaultApps(RegistryName); // Wait until all associations are set int unsetCount = unset.Length; bool hasPrinted = false; while (unsetCount > 0) { Thread.Sleep(500); unset = GetUnset(); if (unset.Length != unsetCount) { unsetCount = unset.Length; if (hasPrinted) { Console.CursorTop--; Console.Write(new string(' ', Console.BufferWidth)); Console.CursorTop--; } if (unsetCount > 1) { Console.WriteLine($"{unsetCount} left."); } else if (unsetCount == 1) { Console.WriteLine("Last one."); } hasPrinted = true; } } } else { Console.WriteLine("All extensions are already associated with the custom types."); } // Whoop Console.WriteLine("Done."); }