Add method to find the add-in directory using Registry lookup
authorThomas
Thu, 26 Nov 2020 11:51:00 +0100
changeset 3349 22667911d471
parent 3348 00e74dc2315d
child 3350 2367e51e7d6b
Add method to find the add-in directory using Registry lookup
ForceProtectionProtocol.cs
Globals.cs
ThisAddIn.cs
--- a/ForceProtectionProtocol.cs	Wed Nov 25 11:59:28 2020 +0100
+++ b/ForceProtectionProtocol.cs	Thu Nov 26 11:51:00 2020 +0100
@@ -869,20 +869,17 @@
             {
                 try
                 {
-                    // Create GPG decryption ProcessStartInfo
-                    var startInfo = new ProcessStartInfo
-                    {
-                        FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sq.exe"),
-                        Arguments = $"--force decrypt --output \"{ decryptedFileName }\" --secret-key-file \"{ keyFile }\" \"{ fileName }\"",
-                        RedirectStandardError = true,
-                        UseShellExecute = false,
-                        CreateNoWindow = true
-                    };
-
                     // Create decryption process and start it
                     var process = new Process
                     {
-                        StartInfo = startInfo
+                        StartInfo =  new ProcessStartInfo
+                        {
+                            FileName = Path.Combine(Globals.GetAddInLocation(), "sq.exe"),
+                            Arguments = $"--force decrypt --output \"{ decryptedFileName }\" --secret-key-file \"{ keyFile }\" \"{ fileName }\"",
+                            RedirectStandardError = true,
+                            UseShellExecute = false,
+                            CreateNoWindow = true
+                        }
                     };
                     process.Start();
                     process.WaitForExit(30000); // limit execution time to 30 s
@@ -948,7 +945,7 @@
                 {
                     StartInfo =
                     {
-                        FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sq.exe"),
+                        FileName = Path.Combine(Globals.GetAddInLocation(), "sq.exe"),
                         Arguments = $"--force key generate --userid \"{ userId }\" --export \"{ keyFileName }\"",
                         RedirectStandardError = true,
                         UseShellExecute = false,
@@ -971,7 +968,7 @@
                     {
                         StartInfo =
                         {
-                            FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sq.exe"),
+                            FileName = Path.Combine(Globals.GetAddInLocation(), "sq.exe"),
                             Arguments = $"--force encrypt --recipient-key-file \"{ keyFileName }\" --output \"{ encryptedFileName }\" \"{ fileName }\"",
                             RedirectStandardError = true,
                             UseShellExecute = false,
--- a/Globals.cs	Wed Nov 25 11:59:28 2020 +0100
+++ b/Globals.cs	Thu Nov 26 11:51:00 2020 +0100
@@ -567,158 +567,6 @@
             return (systemInfo);
         }
 
-        /// <summary>
-        /// Gets the path of the gpg.exe using the install directory from the registry.
-        /// WARNING: this method can return a null path.
-        /// </summary>
-        /// <returns>The path of the gpg.exe, otherwise null.</returns>
-        public static string GetGPGPath()
-        {
-            try
-            {
-                foreach (var gpg4WinPath in TryToGuessGpg4WinPaths())
-                {
-                    var gpgPath = Path.Combine(gpg4WinPath, "..", "GnuPG", "bin", "gpg.exe");
-                    if (File.Exists(gpgPath))
-                    {
-                        return gpgPath;
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                /* As we do not expext any exceptions to actually appear at this level,
-                 * we log them (even in non-verbose mode).
-                 */
-                Log.Error("GetGpaPath: " + ex.Message);
-            }
-
-            return null;
-        }
-
-        /// <summary>
-        /// Gets the path of the GPA .exe using the install directory from the registry.
-        /// WARNING: this method can return a null path.
-        /// </summary>
-        /// <returns>The path of the GPA .exe, otherwise null.</returns>
-        public static string GetGPAPath()
-        {
-            /* We put a general catch block around here, just to be safe - disabling
-             * the GPA button is the better alternative to crashing if something goes
-             * wrong here. 
-             */
-            try
-            {
-                foreach (var gpgPath in TryToGuessGpg4WinPaths())
-                {
-                    var gpaPath = Path.Combine(gpgPath, "bin", "gpa.exe");
-                    if (File.Exists(gpaPath))
-                    {
-                        return gpaPath;
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                /* As we do not expext any exceptions to actually appear at this level,
-                 * we log them (even in non-verbose mode).
-                 */
-                Log.Error("GetGpaPath: " + ex.Message);
-            }
-
-            return null;
-        }
-
-        /// <summary>
-        /// Helper method which tries to find possible Gpg4win installation pathes, with
-        /// decreasing confidence level.
-        /// </summary>
-        /// <returns>A collection of possible Gpg4win paths.</returns>
-        private static IEnumerable<string> TryToGuessGpg4WinPaths()
-        {
-            /* We just try all possible registry views to find GPA. As we just start it as an external process,
-             * we don't care whether it's 32 bit or 64 bit and whether it's in the local machine or current 
-             * user scope.
-             */
-            string gpgPath = null;
-
-            // First, try HKLM and 32 bit
-            gpgPath = TryToReadGpg4winPathFromRegistry(RegistryHive.LocalMachine, RegistryView.Registry32);
-
-            if (string.IsNullOrEmpty(gpgPath) == false)
-            {
-                yield return gpgPath;
-            }
-
-            // Second, try HKCU and 32 bit
-            gpgPath = TryToReadGpg4winPathFromRegistry(RegistryHive.CurrentUser, RegistryView.Registry32);
-
-            if (string.IsNullOrEmpty(gpgPath) == false)
-            {
-                yield return gpgPath;
-            }
-
-            // Third, try HKLM and 64 bit
-            gpgPath = TryToReadGpg4winPathFromRegistry(RegistryHive.LocalMachine, RegistryView.Registry64);
-
-            if (string.IsNullOrEmpty(gpgPath) == false)
-            {
-                yield return gpgPath;
-            }
-
-            // Fourth, try HKCU and 64 bit
-            gpgPath = TryToReadGpg4winPathFromRegistry(RegistryHive.CurrentUser, RegistryView.Registry64);
-
-            if (string.IsNullOrEmpty(gpgPath) == false)
-            {
-                yield return gpgPath;
-            }
-
-            /* Use backup hardcoded directory locations as fallbacks. However, we log this issue
-             * as it is not expected (broken installation?)
-             */
-            Log.Warning("TryToGuessGpgPathes: Not found in registry, trying backup hard-coded directory pathes.");
-
-            yield return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Gpg4win");
-
-            yield return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Gpg4win");
-
-            yield return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Gpg4win");
-
-            yield return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "Gpg4win");
-        }
-
-        /// <summary>
-        /// Helper method that looks up the install directory of the Gpg4win path in the registry.
-        /// </summary>
-        /// <param name="hKey">The registry hive to search (Local Machine or Current User).</param>
-        /// <param name="view">The registry view to search (32 bit or 64 bit).</param>
-        /// <returns>The path to the Gpg4win install directory or null if none was found.</returns>
-        private static string TryToReadGpg4winPathFromRegistry(RegistryHive hKey, RegistryView view)
-        {
-            string gpgPath = null;
-
-            try
-            {
-                using (var rootKey = RegistryKey.OpenBaseKey(hKey, view))
-                {
-                    using (RegistryKey rk = rootKey.OpenSubKey("SOFTWARE\\Gpg4win"))
-                    {
-                        gpgPath = rk?.GetValue("Install Directory") as string;
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                // Exceptions here are expected (the key does not exist in the view we currently 
-                // tried), thus we only long them in verbose mode.
-                Log.Verbose("TryToReadGpg4winPathFromRegistry: " + ex.Message);
-                return null;
-            }
-
-            return gpgPath;
-        }
-
         /**************************************************************
          * 
          * Event Handling
@@ -744,6 +592,35 @@
         }
 
         /// <summary>
+        /// Gets the add-in#s location based on the Registry entry.
+        /// </summary>
+        /// <returns>The full path to the add-in or null if not found.</returns>
+        internal static string GetAddInLocation()
+        {
+            string registryLocation = @"SOFTWARE\Microsoft\Office\Outlook\Addins\pEp";
+            string registryLocation64 = registryLocation.Replace("Software", @"Software\WOW6432Node");
+            using (RegistryKey rkcu = Registry.CurrentUser.OpenSubKey(registryLocation))
+            using (RegistryKey rkcu64 = Registry.CurrentUser.OpenSubKey(registryLocation64))
+            using (RegistryKey rklm = Registry.LocalMachine.OpenSubKey(registryLocation))
+            using (RegistryKey rklm64 = Registry.LocalMachine.OpenSubKey(registryLocation64))
+            {
+                foreach (var regKey in new [] { rkcu, rkcu64, rklm, rklm64 })
+                {
+                    if (regKey?.GetValue("Manifest") is string manifest)
+                    {
+                        Log.Verbose("GetAddInLocation: Found manifest: " + manifest);
+                        string addInLocation = manifest?.Replace("file:///", "")?.Replace("pEp.vsto|vstolocal", "");
+                        Log.Verbose("GetAddInLocation: Returning add-in location " + addInLocation);
+                        return addInLocation;
+                    }
+                }
+            }
+
+            Log.ErrorAndFailInDebugMode("GetAddInLocation: Error getting add-in location. No Registry entry found.");
+            return null;
+        }
+
+        /// <summary>
         /// Searches several Registry locations and gathers the paths of all installed Outlook executables (Outlook.exe).
         /// </summary>
         /// <returns>A HashSet containing the paths of all found Outlook executables.</returns>
--- a/ThisAddIn.cs	Wed Nov 25 11:59:28 2020 +0100
+++ b/ThisAddIn.cs	Thu Nov 26 11:51:00 2020 +0100
@@ -2202,13 +2202,19 @@
         private void ThisAddIn_Startup(object sender, EventArgs e)
         {
 #if DEBUG
+            // Raise WPF binding warnings as errors
             WPFBindingExceptionListener.Attach();
 
-            // In Debug mode, launch adapter if needed
+            // Launch adapter if needed
             if (Process.GetProcessesByName("pEpCOMServerAdapter")?.Length < 1)
             {
                 Process.Start(Path.Combine(Environment.CurrentDirectory, "..", "..", "..", "..", "pEpForWindowsAdapterSolution", "Debug", "pEpCOMServerAdapter.exe"));
             }
+
+            // Copy the executable from the Sequoia directory to the test output directory
+            File.Copy(Path.Combine(Environment.CurrentDirectory, "..", "..", "..", "..", "pEpForWindowsAdapterSolution", "sequoia", "target", "debug", "sq.exe"),
+                      Path.Combine(Globals.GetAddInLocation(), "sq.exe"),
+                      true);
 #endif
             // Set main thread id
             this.mainThreadId = Thread.CurrentThread.ManagedThreadId;