private static void CheckFileExtension_VerifySystemDefaults(IssueTracker Issues, string ExpectedPerceivedType, string Extension, string ExpectedSystemProgid)
        {
            // The standard image formats have a direct association in the (default value) of their extension, and then the same thing
            // in the Progid. Both are in HKLM only. E.g. ".jpg" -> default value is "jpegfile", "OpenWithProgids" contains "jpegfile" (empty string).
            var Key = Registry.LocalMachine.OpenSubKey($@"software\classes\{Extension}");

            if (Key == null)
            {
                Issues.Issue($"Extension key {Extension} missing in HKLM.");
                return;
            }
            var DefaultValue = Key.GetValue(null) as string;

            if (!Util.EqualsOICSafe(DefaultValue, ExpectedSystemProgid))
            {
                Issues.Issue($"Extension key {Extension}'s (HKLM) default value is {DefaultValue}, but {ExpectedSystemProgid} was expected.");
            }
            var Key_OpenWithProgids = Key.OpenSubKey("openwithprogids");

            string[] OpenWithProgids = Key_OpenWithProgids?.GetValueNames();
            if (OpenWithProgids == null)
            {
                Issues.Issue($"{Extension} (HKLM) doesn't contain OpenWithProgids, but it should.");
            }
            else
            {
                bool ContainsOpenWithProgid = OpenWithProgids.Any(x => Util.EqualsOICSafe(x, ExpectedSystemProgid));
                if (!ContainsOpenWithProgid)
                {
                    Issues.Issue($"OpenWithProgids in {Extension} (HKLM) doesn't contain {ExpectedSystemProgid}. Available entries: {string.Join(",", OpenWithProgids)}");
                }
            }

            CheckPerceivedType(Issues, ExpectedPerceivedType, Key, Extension);
        }
        private static void CheckFileExtension_ContainsProgid(IssueTracker Issues, bool Install, string ThisApplicationProgid, string Extension)
        {
            // For our association, we want to add our progid to the HCKU extension's OpenWithProgids.
            // So HKCU\software\classes\.jpg\openwithprogids
            //  -> "Progid" : (empty string)
            // Putting it in "jpegfile" doesn't work.
            // Using a custom verb has issues with the open with menu and is awkward. So this is probably still a better solution.
            var Key = Registry.CurrentUser.OpenSubKey($@"software\classes\{Extension}", writable: Install);

            if (Key == null)
            {
                Issues.Issue($"HKCU key for {Extension} doesn't exist.");
                if (Install)
                {
                    Key = Registry.CurrentUser.CreateSubKey($@"software\classes\{Extension}");
                    Issues.Info($"Created extension \"{Extension}\" in HKCU.");
                }
                else
                {
                    return;
                }
            }

            Debug.Assert(Key != null);

            var Key_OpenWithProgids = Key.OpenSubKey("openwithprogids", writable: Install);

            if (Key_OpenWithProgids == null)
            {
                Issues.Issue($"HKCU key for {Extension} doesn't have OpenWithProgids.");
                if (Install)
                {
                    Key_OpenWithProgids = Key.CreateSubKey("OpenWithProgids");
                    Issues.Info($"Created OpenWithProgids in \"{Extension}\".");
                }
                else
                {
                    return;
                }
            }

            Debug.Assert(Key_OpenWithProgids != null);

            bool HaveProgid = Key_OpenWithProgids.GetValueNames().Any(x => Util.EqualsOICSafe(x, ThisApplicationProgid));

            if (!HaveProgid)
            {
                Issues.Issue($"HKCU key for {Extension} doesn't contain Progid {ThisApplicationProgid} in OpenWithProgids.");
                if (Install)
                {
                    Key_OpenWithProgids.SetValue(ThisApplicationProgid, string.Empty, RegistryValueKind.String);
                    Issues.Info($"Added Progid in \"{Extension}\": \"{ThisApplicationProgid}\".");
                }
            }
        }
        private static void CheckPerceivedType(IssueTracker Issues, string ExpectedPerceivedType, RegistryKey Key_HKLM, string Extension)
        {
            // HKLM extension keys (".jpg" etc) should have perceived type "image".
            string PerceivedType = Key_HKLM.GetValue("perceivedtype") as string;

            if (PerceivedType == null)
            {
                Issues.Issue($"Perceived type in \"{Extension}\" is missing (expected \"{ExpectedPerceivedType}\")");
            }
            else if (!Util.EqualsOICSafe(PerceivedType, ExpectedPerceivedType))
            {
                Issues.Issue($"Perceived type in \"{Extension}\" ({PerceivedType}) seems wrong (expected \"{ExpectedPerceivedType}\")");
            }
        }
        private static void CheckUserChoice(IssueTracker Issues, string Extension, string Progid)
        {
            // Check whether a program *other* than Progid is written in the UserChoice key of the extension.
            // If that key doesn't exist, or if no user choice is available, that's also OK. The point here is to make sure that Windows asks
            // the user which program it should use the next time any file with that extension is opened.
            var Key = Registry.CurrentUser.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{Extension}");

            if (Key == null)
            {
                return;
            }

            var Key_UserChoice = Key.OpenSubKey("userchoice");

            if (Key_UserChoice == null)
            {
                return;
            }

            string CurrentProgid = Key_UserChoice.GetValue("progid") as string;

            if (CurrentProgid == null || Util.EqualsOICSafe(CurrentProgid, Progid))
            {
                return;
            }

            Issues.Issue($"UserChoice for {Extension} is \"{CurrentProgid}\", but \"{Progid}\" was expected.");
        }
        private static void CheckFileHandlerVerbsInternal(IssueTracker Issues, string FileHandlerName, RegistryKey Key)
        {
            var Key_Shell = Key.OpenSubKey("shell");

            if (Key_Shell == null)
            {
                return;                 // No shell - no verbs. That's is OK in this case.
            }
            string DefaultVerb = Key_Shell.GetValue(string.Empty) as string;

            if (DefaultVerb != null)
            {
                Issues.Issue($"{FileHandlerName} has explicit default verb \"{DefaultVerb}\", which is unexpected.");
            }

            var Key_Open = Key_Shell.OpenSubKey("open");

            if (Key_Open != null)
            {
                Issues.Issue($"Key {Key} has open verb, even though it shouldn't.");
            }
        }
        private static void CheckFileHandlerVerbs(IssueTracker Issues, string FileHandlerName)
        {
            // None of the image extension keys (".jpg" etc), nor file handlers ("jpegfile" etc) should have an "open" verb, except giffile.
            var Key_HKLM = Registry.LocalMachine.OpenSubKey($@"software\classes\{FileHandlerName}");

            if (Key_HKLM == null)
            {
                Issues.Issue($"{FileHandlerName} not found in HKLM.");
            }
            else
            {
                CheckFileHandlerVerbsInternal(Issues, FileHandlerName, Key_HKLM);
            }

            var Key_HKCU = Registry.CurrentUser.OpenSubKey($@"software\classes\{FileHandlerName}");

            if (Key_HKCU != null)             // This one's optional
            {
                CheckFileHandlerVerbsInternal(Issues, FileHandlerName, Key_HKCU);
            }
        }
        private static void CheckProgidKey(IssueTracker Issues, bool Install, string Progid, string ExpectedCommand, string FriendlyAppName)
        {
            // Check that the progid key exists in HKCU classes, and that it has a valid open verb as its only verb.
            var Key = Registry.CurrentUser.OpenSubKey($@"software\classes\{Progid}", writable: Install);

            if (Key == null)
            {
                Issues.Issue($"ProgidKey {Progid} doesn't exist in HKCU.");
                if (Install)
                {
                    Key = Registry.CurrentUser.CreateSubKey($@"software\classes\{Progid}");
                    Issues.Info($"Created Progid key for {Progid} in HKCU.");
                }
                else
                {
                    return;
                }
            }

            Debug.Assert(Key != null);

            var Key_Shell = Key.OpenSubKey("shell", writable: Install);

            if (Key_Shell == null)
            {
                Issues.Issue($"ProgidKey {Progid} doesn't have shell in HKCU.");
                if (Install)
                {
                    Key_Shell = Key.CreateSubKey("shell");
                    Issues.Info($"shell subkey created in {Progid}.");
                }
                else
                {
                    return;
                }
            }

            Debug.Assert(Key_Shell != null);

            foreach (string ShellSubKey in Key_Shell.GetSubKeyNames())
            {
                if (!Util.EqualsOICSafe(ShellSubKey, "open"))
                {
                    Issues.Issue($"ProgidKey {Progid} contains verb {ShellSubKey}, which isn't expected.");
                    if (Install)
                    {
                        Key_Shell.DeleteSubKeyTree(ShellSubKey);
                        Issues.Info($"Verb \"{ShellSubKey}\" deleted in Progid {Progid}.");
                    }
                }
            }

            var Key_Open = Key_Shell.OpenSubKey("open", writable: Install);

            if (Key_Open == null)
            {
                Issues.Issue($"ProgidKey {Progid} doesn't have an open verb.");
                if (Install)
                {
                    Key_Open = Key_Shell.CreateSubKey("open");
                    Issues.Info($"Created open verb in ProgidKey {Progid}");
                }
                else
                {
                    return;
                }
            }

            Debug.Assert(Key_Open != null);

            string CurrentFriendlyAppName = Key_Open.GetValue("FriendlyAppName") as string;

            if (CurrentFriendlyAppName != FriendlyAppName)
            {
                Issues.Issue($"ProgidKey {Progid}'s open verb has incorrect FriendlyAppName \"{CurrentFriendlyAppName}\"; expected \"{FriendlyAppName}\".");
                if (Install)
                {
                    if (FriendlyAppName != null)
                    {
                        Key_Open.SetValue("FriendlyAppName", FriendlyAppName, RegistryValueKind.String);
                        Issues.Info($"FriendlyAppName for {Progid} set to \"{FriendlyAppName}\".");
                    }
                    else
                    {
                        Key_Open.DeleteValue("FriendlyAppName");
                        Issues.Info($"FriendlyAppName for {Progid} removed.");
                    }
                }
            }

            var Key_Command = Key_Open.OpenSubKey("command", writable: Install);

            if (Key_Command == null)
            {
                Issues.Issue($"ProgidKey {Progid}'s open verb doesn't have a command subkey.");
                if (Install)
                {
                    Key_Command = Key_Open.CreateSubKey("command");
                    Issues.Info($"Created command in {Progid}'s open verb.");
                }
                else
                {
                    return;
                }
            }

            Debug.Assert(Key_Command != null);

            string Command = Key_Command.GetValue(null) as string;

            if (!Util.EqualsOICSafe(Command, ExpectedCommand))
            {
                Issues.Issue($"ProgidKey {Progid}'s open verb command is {{{Command}}}, but {{{ExpectedCommand}}} was expected.");
                if (Install)
                {
                    Key_Command.SetValue(null, ExpectedCommand);
                    Issues.Info($"Changed command in {Progid}'s open verb to {{{ExpectedCommand}}}.");
                }
            }
        }