Improve apphost missing fxr error message with self registered location (dotnet/core...
authorVitek Karas <vitek.karas@microsoft.com>
Wed, 29 May 2019 04:43:54 +0000 (21:43 -0700)
committerGitHub <noreply@github.com>
Wed, 29 May 2019 04:43:54 +0000 (21:43 -0700)
With the recent changes apphost now looks for shared framework in 3 potential places: the default global location, the globally registered location and the DOTNET_ROOT path.
The error message didn't mention the globally registered location, so add that.

Required a bit of refactoring in the pals to avoid code duplication.

Commit migrated from https://github.com/dotnet/core-setup/commit/832f8250b5986028594c0db47b4e1cb62915c15b

src/installer/corehost/cli/fxr_resolver.cpp
src/installer/corehost/common/pal.h
src/installer/corehost/common/pal.unix.cpp
src/installer/corehost/common/pal.windows.cpp

index b838e6f..3eb652c 100644 (file)
@@ -102,13 +102,22 @@ bool fxr_resolver::try_get_path(const pal::string_t& root_path, pal::string_t* o
             pal::get_default_installation_dir(&default_install_location);
         }
 
+        pal::string_t self_registered_config_location;
+        pal::string_t self_registered_message;
+        if (pal::get_dotnet_self_registered_config_location(&self_registered_config_location))
+        {
+            self_registered_message =
+                pal::string_t(_X(" or register the runtime location in [") + self_registered_config_location + _X("]"));
+        }
+
         trace::error(_X("A fatal error occurred. The required library %s could not be found.\n"
             "If this is a self-contained application, that library should exist in [%s].\n"
-            "If this is a framework-dependent application, install the runtime in the global location [%s] or use the %s environment variable to specify the runtime location."),
+            "If this is a framework-dependent application, install the runtime in the global location [%s] or use the %s environment variable to specify the runtime location%s."),
             LIBFXR_NAME,
             root_path.c_str(),
             default_install_location.c_str(),
-            dotnet_root_env_var_name.c_str());
+            dotnet_root_env_var_name.c_str(),
+            self_registered_message.c_str());
         return false;
     }
 #else // !FEATURE_APPHOST && !FEATURE_LIBHOST
index a0b90fa..ec9aae1 100644 (file)
@@ -267,6 +267,8 @@ namespace pal
 
     // Returns the globally registered install location (if any)
     bool get_dotnet_self_registered_dir(pal::string_t* recv);
+    // Returns name of the global registry location (for error messages)
+    bool get_dotnet_self_registered_config_location(pal::string_t* recv);
 
     // Returns the default install location for a given platform
     bool get_default_installation_dir(pal::string_t* recv);
index a3298f6..f830adc 100644 (file)
@@ -299,6 +299,20 @@ bool pal::get_global_dotnet_dirs(std::vector<pal::string_t>* recv)
     return false;
 }
 
+bool pal::get_dotnet_self_registered_config_location(pal::string_t* recv)
+{
+    *recv = _X("/etc/dotnet/install_location");
+
+    //  ***Used only for testing***
+    pal::string_t environment_install_location_override;
+    if (test_only_getenv(_X("_DOTNET_TEST_INSTALL_LOCATION_FILE_PATH"), &environment_install_location_override))
+    {
+        *recv = environment_install_location_override;
+    }
+
+    return true;
+}
+
 bool pal::get_dotnet_self_registered_dir(pal::string_t* recv)
 {
     recv->clear();
@@ -312,13 +326,10 @@ bool pal::get_dotnet_self_registered_dir(pal::string_t* recv)
     }
     //  ***************************
 
-    pal::string_t install_location_file_path = _X("/etc/dotnet/install_location");
-
-    //  ***Used only for testing***
-    pal::string_t environment_install_location_override;
-    if (test_only_getenv(_X("_DOTNET_TEST_INSTALL_LOCATION_FILE_PATH"), &environment_install_location_override))
+    pal::string_t install_location_file_path;
+    if (!get_dotnet_self_registered_config_location(&install_location_file_path))
     {
-        install_location_file_path = environment_install_location_override;
+        return false;
     }
     //  ***************************
 
index 53089b7..0b65d3d 100644 (file)
@@ -250,6 +250,47 @@ bool pal::get_default_installation_dir(pal::string_t* recv)
     return true;
 }
 
+namespace
+{
+    void get_dotnet_install_location_registry_path(HKEY * key_hive, pal::string_t * sub_key, pal::char_t ** value)
+    {
+        *key_hive = HKEY_LOCAL_MACHINE;
+        // The registry search occurs in the 32-bit registry in all cases.
+        pal::string_t dotnet_key_path = pal::string_t(_X("SOFTWARE\\dotnet"));
+
+        pal::string_t environmentRegistryPathOverride;
+        if (test_only_getenv(_X("_DOTNET_TEST_REGISTRY_PATH"), &environmentRegistryPathOverride))
+        {
+            pal::string_t hkcuPrefix = _X("HKEY_CURRENT_USER\\");
+            if (environmentRegistryPathOverride.substr(0, hkcuPrefix.length()) == hkcuPrefix)
+            {
+                *key_hive = HKEY_CURRENT_USER;
+                environmentRegistryPathOverride = environmentRegistryPathOverride.substr(hkcuPrefix.length());
+            }
+
+            dotnet_key_path = environmentRegistryPathOverride;
+        }
+
+        *sub_key = dotnet_key_path + pal::string_t(_X("\\Setup\\InstalledVersions\\")) + get_arch();
+        *value = _X("InstallLocation");
+    }
+}
+
+bool pal::get_dotnet_self_registered_config_location(pal::string_t* recv)
+{
+#if !defined(_TARGET_AMD64_) && !defined(_TARGET_X86_)
+    return false;
+#else
+    HKEY key_hive;
+    pal::string_t sub_key;
+    pal::char_t* value;
+    get_dotnet_install_location_registry_path(&key_hive, &sub_key, &value);
+
+    *recv = (key_hive == HKEY_CURRENT_USER ? _X("HKCU\\") : _X("HKLM\\")) + sub_key + _X("\\") + value;
+    return true;
+#endif
+}
+
 bool pal::get_dotnet_self_registered_dir(pal::string_t* recv)
 {
 #if !defined(_TARGET_AMD64_) && !defined(_TARGET_X86_)
@@ -267,26 +308,10 @@ bool pal::get_dotnet_self_registered_dir(pal::string_t* recv)
     }
     //  ***************************
 
-    DWORD size = 0;
-    HKEY hkeyHive = HKEY_LOCAL_MACHINE;
-    // The registry search occurs in the 32-bit registry in all cases.
-    pal::string_t dotnet_key_path = pal::string_t(_X("SOFTWARE\\dotnet"));
-
-    pal::string_t environmentRegistryPathOverride;
-    if (test_only_getenv(_X("_DOTNET_TEST_REGISTRY_PATH"), &environmentRegistryPathOverride))
-    {
-        pal::string_t hkcuPrefix = _X("HKEY_CURRENT_USER\\");
-        if (environmentRegistryPathOverride.substr(0, hkcuPrefix.length()) == hkcuPrefix)
-        {
-            hkeyHive = HKEY_CURRENT_USER;
-            environmentRegistryPathOverride = environmentRegistryPathOverride.substr(hkcuPrefix.length());
-        }
-
-        dotnet_key_path = environmentRegistryPathOverride;
-    }
-
-    pal::string_t sub_key = dotnet_key_path + pal::string_t(_X("\\Setup\\InstalledVersions\\")) + get_arch();
-    pal::char_t* value = _X("InstallLocation");
+    HKEY hkeyHive;
+    pal::string_t sub_key;
+    pal::char_t* value;
+    get_dotnet_install_location_registry_path(&hkeyHive, &sub_key, &value);
 
     // Must use RegOpenKeyEx to be able to specify KEY_WOW64_32KEY to access the 32-bit registry in all cases.
     // The RegGetValue has this option available only on Win10.
@@ -299,6 +324,7 @@ bool pal::get_dotnet_self_registered_dir(pal::string_t* recv)
     }
 
     // Determine the size of the buffer
+    DWORD size = 0;
     result = ::RegGetValueW(hkey, nullptr, value, RRF_RT_REG_SZ, nullptr, nullptr, &size);
     if (result != ERROR_SUCCESS || size == 0)
     {