summaryrefslogtreecommitdiff
path: root/src/utilcode/clrconfig.cpp
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/utilcode/clrconfig.cpp
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/utilcode/clrconfig.cpp')
-rw-r--r--src/utilcode/clrconfig.cpp777
1 files changed, 777 insertions, 0 deletions
diff --git a/src/utilcode/clrconfig.cpp b/src/utilcode/clrconfig.cpp
new file mode 100644
index 0000000000..0b164694d4
--- /dev/null
+++ b/src/utilcode/clrconfig.cpp
@@ -0,0 +1,777 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+//*****************************************************************************
+// CLRConfig.cpp
+//
+
+//
+// Unified method of accessing configuration values from environment variables,
+// registry and config file. See file:../inc/CLRConfigValues.h for details on how to add config values.
+//
+//*****************************************************************************
+
+#include "stdafx.h"
+#include "clrconfig.h"
+
+#ifndef ERANGE
+#define ERANGE 34
+#endif
+
+//
+// Initialize the EEConfig::GetConfiguration function pointer to NULL. If EEConfig isn't init'ed, this will
+// stay NULL and CLRConfig will ignore config files.
+//
+CLRConfig::GetConfigValueFunction CLRConfig::s_GetConfigValueCallback = NULL;
+
+//
+// Initialize the PerformanceDefaults::LookupConfigValue function pointer to NULL. If not initialized, CLRConfig
+// will ignore LookupOptions::MayHavePerformanceDefault.
+//
+CLRConfig::GetPerformanceDefaultValueFunction CLRConfig::s_GetPerformanceDefaultValueCallback = NULL;
+
+#ifdef FEATURE_WIN_DB_APPCOMPAT
+PFN_CptQuirkIsEnabled3 CLRConfig::s_IsQuirkEnabledCallback = NULL;
+PFN_CptQuirkGetData2 CLRConfig::s_GetQuirkValueCallback = NULL;
+#endif
+
+//
+// Creating structs using the macro table in CLRConfigValues.h
+//
+
+// These macros intialize ConfigDWORDInfo structs.
+#define RETAIL_CONFIG_DWORD_INFO(symbol, name, defaultValue, description) \
+ const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, CLRConfig::EEConfig_default};
+#define RETAIL_CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions) \
+ const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, lookupOptions};
+
+// These macros intialize ConfigStringInfo structs.
+#define RETAIL_CONFIG_STRING_INFO(symbol, name, description) \
+ const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, CLRConfig::EEConfig_default};
+#define RETAIL_CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions) \
+ const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, lookupOptions};
+
+// TEMPORARY macros that intialize strings for config value accesses that haven't been moved over to
+// CLRConfig yet. Once all accesses have been moved, these macros (and corresponding instantiations in
+// file:../utilcode/CLRConfig.h) should be removed.
+#define RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description) \
+ const LPCWSTR CLRConfig::symbol = name;
+#define RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description) \
+ const LPCWSTR CLRConfig::symbol = name;
+//
+// Debug versions of the macros
+//
+#ifdef _DEBUG
+ #define CONFIG_DWORD_INFO(symbol, name, defaultValue, description) \
+ const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, CLRConfig::EEConfig_default};
+ #define CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions) \
+ const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, lookupOptions};
+ #define CONFIG_STRING_INFO(symbol, name, description) \
+ const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, CLRConfig::EEConfig_default};
+ #define CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions) \
+ const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, lookupOptions};
+ #define CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description) \
+ const LPCWSTR CLRConfig::symbol = name;
+ #define CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description) \
+ const LPCWSTR CLRConfig::symbol = name;
+#else
+ #define CONFIG_DWORD_INFO(symbol, name, defaultValue, description)
+ #define CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions)
+ #define CONFIG_STRING_INFO(symbol, name, description)
+ #define CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions)
+ #define CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description)
+ #define CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description)
+#endif // _DEBUG
+
+ // Now that we have defined what what the macros in file:../inc/CLRConfigValues.h mean, include it to generate the code.
+ #include "clrconfigvalues.h"
+
+#undef RETAIL_CONFIG_DWORD_INFO
+#undef RETAIL_CONFIG_STRING_INFO
+#undef RETAIL_CONFIG_DWORD_INFO_EX
+#undef RETAIL_CONFIG_STRING_INFO_EX
+#undef RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS
+#undef RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS
+#undef CONFIG_DWORD_INFO
+#undef CONFIG_STRING_INFO
+#undef CONFIG_DWORD_INFO_EX
+#undef CONFIG_STRING_INFO_EX
+#undef CONFIG_DWORD_INFO_DIRECT_ACCESS
+#undef CONFIG_STRING_INFO_DIRECT_ACCESS
+
+
+#ifdef FEATURE_WIN_DB_APPCOMPAT
+
+#define MAX_QUIRK_LENGTH 60
+#define WIN_DB_COMPONENT_NAME W("NETFX.")
+#define WIN_DB_COMPONENT_NAME_LENGTH 6
+
+// queries the DB if the quirk is enabled. If the quirk is enabled then it also gets the value associated with the quirk.
+// pass in quirkData as NULL if the value is not required and only enabled/disabled is needed.
+// Length of quirk cannot be greater than 60. If it is greater than 60 then this api returns E_FAIL.
+HRESULT CLRConfig::getQuirkEnabledAndValueFromWinDB(LPCWSTR wszQuirkName, BOOL* isEnabled, CPT_QUIRK_DATA* quirkData)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ PRECONDITION(CheckPointer(isEnabled, NULL_NOT_OK));
+ }
+ CONTRACTL_END;
+
+ if(wszQuirkName == NULL)
+ return E_FAIL;
+
+ WCHAR wszCompleteQuirkName[MAX_QUIRK_LENGTH + WIN_DB_COMPONENT_NAME_LENGTH + 1];
+ WCHAR wszComponentName[] = WIN_DB_COMPONENT_NAME;
+ size_t cchCompleteQuirkName = MAX_QUIRK_LENGTH + WIN_DB_COMPONENT_NAME_LENGTH + 1;
+
+ _ASSERT(wcslen(wszComponentName) == WIN_DB_COMPONENT_NAME_LENGTH);
+
+ size_t cchOrig = wcslen(wszQuirkName);
+ if(cchOrig > MAX_QUIRK_LENGTH)
+ {
+ return E_FAIL;
+ }
+
+ // Create comlete name of the quirk. Windows expects complete quirkName i.e. componentName.quirkName
+ // eg. ETWEnabled will become NETFX.ETWEnabled
+ errno_t err = wcsncpy_s(wszCompleteQuirkName, cchCompleteQuirkName, wszComponentName, WIN_DB_COMPONENT_NAME_LENGTH);
+ if (err != 0)
+ {
+ return E_FAIL;
+ }
+
+ err = wcscat_s(wszCompleteQuirkName, cchCompleteQuirkName, wszQuirkName);
+ if (err != 0)
+ {
+ return E_FAIL;
+ }
+
+
+ UINT32 version = 0xFFFFFFFF;
+ BOOL fIsEnabled;
+ //call windows api
+ // Version passed must be 0xFFFFFFFF for NETFX. Passing any other version requires more
+ // understanding of the windows API.
+ fIsEnabled = s_IsQuirkEnabledCallback(wszCompleteQuirkName,version);
+
+ if(fIsEnabled && quirkData != NULL)
+ {
+ quirkData->Size = sizeof(CPT_QUIRK_DATA);
+ // Query for quirkData
+ if(!SUCCEEDED(s_GetQuirkValueCallback(wszCompleteQuirkName, quirkData)))
+ {
+ return E_FAIL;
+ }
+ }
+
+ *isEnabled = fIsEnabled;
+
+ return S_OK;
+}
+
+#endif
+
+
+// Return if a quirk is a enabled.
+// This will also return enabled as true when the quirk has a value set.
+BOOL CLRConfig::IsConfigEnabled(const ConfigDWORDInfo & info)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ FORBID_FAULT;
+ SO_INTOLERANT;
+ }
+ CONTRACTL_END;
+
+ DWORD result = info.defaultValue;
+
+#ifdef FEATURE_WIN_DB_APPCOMPAT
+ // Windows Shim DB should be the first place to look as it applies microsoft enforced policy
+ // and overrides setting at any other place like config or registry
+ if(CheckLookupOption(info, IgnoreWindowsQuirkDB) == FALSE &&
+ s_IsQuirkEnabledCallback != NULL )// Check that IsQuirkEnabledCallback function has been registered.
+ {
+ BOOL enabledInDB = FALSE;
+ if(SUCCEEDED(getQuirkEnabledAndValueFromWinDB(info.name, &enabledInDB, NULL)))
+ {
+ if(enabledInDB)
+ {
+ return TRUE;
+ }
+ }
+ }
+#endif
+ //
+ // Set up REGUTIL options.
+ //
+ REGUTIL::CORConfigLevel level = GetConfigLevel(info.options);
+ BOOL prependCOMPLUS = !CheckLookupOption(info, DontPrependCOMPLUS_);
+
+ //
+ // If we aren't favoring config files, we check REGUTIL here.
+ //
+ if(CheckLookupOption(info, FavorConfigFile) == FALSE)
+ {
+ REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPLUS);
+ if(result>0)
+ return TRUE;
+ LPWSTR result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPLUS, level);
+ if(result != NULL && result[0] != 0)
+ {
+ return TRUE;
+ }
+ }
+
+ //
+ // Check config files through EEConfig.
+ //
+ if(CheckLookupOption(info, IgnoreConfigFiles) == FALSE && // Check that we aren't ignoring config files.
+ s_GetConfigValueCallback != NULL)// Check that GetConfigValueCallback function has been registered.
+ {
+ LPCWSTR pvalue;
+
+ // EEConfig lookup options.
+ BOOL systemOnly = CheckLookupOption(info, ConfigFile_SystemOnly) ? TRUE : FALSE;
+ BOOL applicationFirst = CheckLookupOption(info, ConfigFile_ApplicationFirst) ? TRUE : FALSE;
+
+ if(SUCCEEDED(s_GetConfigValueCallback(info.name, &pvalue, systemOnly, applicationFirst)) && pvalue != NULL)
+ {
+ WCHAR * end;
+ errno = 0;
+ result = wcstoul(pvalue, &end, 0);
+
+ // errno is ERANGE if the number is out of range, and end is set to pvalue if
+ // no valid conversion exists.
+ if (errno == ERANGE || end == pvalue)
+ {
+ if(pvalue[0]!=0)
+ return TRUE;
+
+ result = info.defaultValue;
+ }
+
+ if(result>0)
+ return TRUE;
+ }
+ }
+
+ //
+ // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here.
+ //
+ if(CheckLookupOption(info, FavorConfigFile) == TRUE)
+ {
+ REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPLUS);
+ if(result>0)
+ return TRUE;
+ LPWSTR result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPLUS, level);
+ if(result != NULL && result[0] != 0)
+ {
+ return TRUE;
+ }
+ }
+
+ //
+ // If we get here, the option was not listed in REGUTIL or EEConfig; check whether the option
+ // has a PerformanceDefault-specified value before falling back to the built-in default
+ //
+ DWORD performanceDefaultValue;
+ if (CheckLookupOption(info, MayHavePerformanceDefault) &&
+ s_GetPerformanceDefaultValueCallback != NULL &&
+ s_GetPerformanceDefaultValueCallback(info.name, &performanceDefaultValue))
+ {
+ if (!SUCCEEDED(REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPLUS)))
+ {
+ if(performanceDefaultValue>0)
+ return TRUE;
+ }
+ }
+
+ if(info.defaultValue>0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+
+//
+// Look up a DWORD config value.
+//
+// Arguments:
+// * info - see file:../inc/CLRConfig.h for details
+//
+// static
+DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ FORBID_FAULT;
+ SO_TOLERANT; // Need this to be tolerant to stack overflows since REGUTIL::GetConfigDWORD was too. (This replaces calls to REGUTIL::GetConfigDWORD)
+ }
+ CONTRACTL_END;
+
+ DWORD result = info.defaultValue;
+
+#ifdef FEATURE_WIN_DB_APPCOMPAT
+ // Windows Shim DB should be the first place to look as it applies microsoft enforced policy
+ // and overrides setting at any other place like config or registry
+ if(CheckLookupOption(info, IgnoreWindowsQuirkDB) == FALSE &&
+ s_IsQuirkEnabledCallback != NULL )// Check that IsQuirkEnabledCallback function has been registered.
+ {
+
+ BOOL isEnabledInDB = FALSE;
+ CPT_QUIRK_DATA quirkData;
+ if(SUCCEEDED(getQuirkEnabledAndValueFromWinDB(info.name, &isEnabledInDB, &quirkData)))
+ {
+ if(isEnabledInDB)
+ {
+ WCHAR *end;
+ errno = 0;
+ result = wcstoul(quirkData.CommandLine, &end, 0);
+
+ // errno is ERANGE if the number is out of range, and end is set to pvalue if
+ // no valid conversion exists.
+ if (errno != ERANGE && end != quirkData.CommandLine)
+ {
+ return result;
+ }
+ else
+ {
+ // If an invalid value is defined we treat it as the default value.
+ // i.e. we don't look further.
+ return info.defaultValue;
+ }
+ }
+ }
+ }
+#endif // FEATURE_WIN_DB_APPCOMPAT
+
+ //
+ // Set up REGUTIL options.
+ //
+ REGUTIL::CORConfigLevel level = GetConfigLevel(info.options);
+ BOOL prependCOMPLUS = !CheckLookupOption(info, DontPrependCOMPLUS_);
+
+ //
+ // If we aren't favoring config files, we check REGUTIL here.
+ //
+ if(CheckLookupOption(info, FavorConfigFile) == FALSE)
+ {
+ REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPLUS);
+ // TODO: We are ignoring explicitly defined default values to avoid change in behavior.
+ // TODO: Ideally, the following should check the hresult for success.
+ if(result != info.defaultValue)
+ {
+ return result;
+ }
+ }
+
+ //
+ // Check config files through EEConfig.
+ //
+ if(CheckLookupOption(info, IgnoreConfigFiles) == FALSE && // Check that we aren't ignoring config files.
+ s_GetConfigValueCallback != NULL)// Check that GetConfigValueCallback function has been registered.
+ {
+ LPCWSTR pvalue;
+
+ // EEConfig lookup options.
+ BOOL systemOnly = CheckLookupOption(info, ConfigFile_SystemOnly) ? TRUE : FALSE;
+ BOOL applicationFirst = CheckLookupOption(info, ConfigFile_ApplicationFirst) ? TRUE : FALSE;
+
+ if(SUCCEEDED(s_GetConfigValueCallback(info.name, &pvalue, systemOnly, applicationFirst)) && pvalue != NULL)
+ {
+ WCHAR * end;
+ errno = 0;
+ result = wcstoul(pvalue, &end, 0);
+
+ // errno is ERANGE if the number is out of range, and end is set to pvalue if
+ // no valid conversion exists.
+ if (errno != ERANGE && end != pvalue)
+ {
+ return result;
+ }
+ else
+ {
+ // If an invalid value is defined we treat it as the default value.
+ // i.e. we don't look further.
+ return info.defaultValue;
+ }
+ }
+ }
+
+ //
+ // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here.
+ //
+ if(CheckLookupOption(info, FavorConfigFile) == TRUE)
+ {
+ REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPLUS);
+ // TODO: We are ignoring explicitly defined default values to avoid change in behavior.
+ // TODO: Ideally, the following should check the hresult for success.
+ if(result != info.defaultValue)
+ {
+ return result;
+ }
+ }
+
+ //
+ // If we get here, the option was not listed in REGUTIL or EEConfig; check whether the option
+ // has a PerformanceDefault-specified value before falling back to the built-in default
+ //
+ DWORD performanceDefaultValue;
+ if (CheckLookupOption(info, MayHavePerformanceDefault) &&
+ s_GetPerformanceDefaultValueCallback != NULL &&
+ s_GetPerformanceDefaultValueCallback(info.name, &performanceDefaultValue))
+ {
+ // TODO: We ignore explicitly defined default values above, but we do not want to let performance defaults override these.
+ // TODO: Ideally, the above would use hresult for success and this check would be removed.
+ if (!SUCCEEDED(REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPLUS)))
+ return performanceDefaultValue;
+ }
+
+ return info.defaultValue;
+}
+
+//
+// Look up a String config value.
+//
+// Arguments:
+// * info - see file:../inc/CLRConfig.h for details
+//
+// Return value:
+// * Pointer to the string value, if found. You own the string that's returned. Returns NULL if the value
+// is not found.
+//
+// static
+LPWSTR CLRConfig::GetConfigValue(const ConfigStringInfo & info)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ FORBID_FAULT;
+ }
+ CONTRACTL_END;
+
+ LPWSTR result = NULL;
+
+ // TODO: We swallow OOM exception here. Is this OK?
+ FAULT_NOT_FATAL();
+
+ // If this fails, result will stay NULL.
+ GetConfigValue(info, &result);
+
+ return result;
+}
+
+//
+// Look up a string config value, passing it out through a pointer reference.
+//
+// Return value:
+// * Reports out of memory errors (HRESULT E_OUTOFMEMORY).
+//
+// Arguments:
+// * info - see file:../inc/CLRConfig.h for details
+// * outVal - Set to the result string. You own the string that's returned. Set to NULL if the value is
+// not found.
+//
+// static
+HRESULT CLRConfig::GetConfigValue(const ConfigStringInfo & info, __deref_out_z LPWSTR * outVal)
+{
+ CONTRACT(HRESULT) {
+ NOTHROW;
+ GC_NOTRIGGER;
+ INJECT_FAULT (CONTRACT_RETURN E_OUTOFMEMORY);
+ POSTCONDITION(CheckPointer(outVal, NULL_OK)); // TODO: Should this check be *outVal instead of outVal?
+ } CONTRACT_END;
+
+ LPWSTR result = NULL;
+
+#ifdef FEATURE_WIN_DB_APPCOMPAT
+ // Windows Shim DB should be the first place to look as it applies microsoft enforced policy
+ // and overrides setting at any other place like config or registry
+ if(CheckLookupOption(info, IgnoreWindowsQuirkDB) == FALSE &&
+ s_IsQuirkEnabledCallback != NULL )// Check that IsQuirkEnabledCallback function has been registered.
+ {
+
+ BOOL isEnabledInDB = FALSE;
+ CPT_QUIRK_DATA quirkData;
+ if(SUCCEEDED(getQuirkEnabledAndValueFromWinDB(info.name, &isEnabledInDB, &quirkData)))
+ {
+ if(isEnabledInDB)
+ {
+ size_t len = wcslen(quirkData.CommandLine) + 1;
+ result = new (nothrow) WCHAR[len];
+ if (result == NULL)
+ {
+ RETURN E_OUTOFMEMORY;
+ }
+ wcscpy_s(result, len, quirkData.CommandLine);
+ }
+ }
+ }
+#endif // FEATURE_WIN_DB_APPCOMPAT
+
+ //
+ // Set up REGUTIL options.
+ //
+ REGUTIL::CORConfigLevel level = GetConfigLevel(info.options);
+ BOOL prependCOMPLUS = !CheckLookupOption(info, DontPrependCOMPLUS_);
+
+ //
+ // If we aren't favoring config files, we check REGUTIL here.
+ //
+ if(result == NULL && CheckLookupOption(info, FavorConfigFile) == FALSE)
+ {
+ result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPLUS, level);
+ }
+
+ //
+ // Check config files through EEConfig.
+ //
+ if(result == NULL && // Check that we don't have a value from REGUTIL
+ CheckLookupOption(info, IgnoreConfigFiles) == FALSE && // Check that we aren't ignoring config files.
+ s_GetConfigValueCallback != NULL) // Check that GetConfigValueCallback function has been registered.
+ {
+ LPCWSTR pResult;
+
+ // EEConfig lookup options.
+ BOOL systemOnly = CheckLookupOption(info, ConfigFile_SystemOnly) ? TRUE : FALSE;
+ BOOL applicationFirst = CheckLookupOption(info, ConfigFile_ApplicationFirst) ? TRUE : FALSE;
+
+ if(SUCCEEDED(s_GetConfigValueCallback(info.name, &pResult, systemOnly, applicationFirst)) && pResult != NULL)
+ {
+ size_t len = wcslen(pResult) + 1;
+ result = new (nothrow) WCHAR[len];
+ if (result == NULL)
+ {
+ RETURN E_OUTOFMEMORY;
+ }
+ wcscpy_s(result, len, pResult);
+ }
+ }
+
+ //
+ // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here.
+ //
+ if(result==NULL &&
+ CheckLookupOption(info, FavorConfigFile) == TRUE)
+ {
+ result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPLUS, level);
+ }
+
+ if ((result != NULL) && CheckLookupOption(info, TrimWhiteSpaceFromStringValue))
+ {
+ // If this fails, result remains untouched, so we'll just return the untrimmed
+ // value.
+ LPWSTR wszTrimmedResult = NULL;
+ if (SUCCEEDED(TrimWhiteSpace(result, &wszTrimmedResult)) &&
+ (wszTrimmedResult != NULL))
+ {
+ // wszTrimmedResult should be the result we return. Delete the untrimmed
+ // result.
+ delete [] result;
+ result = wszTrimmedResult;
+ }
+ }
+
+ // If we ever want a PerformanceDefault for a string value, you can replace this assert
+ // with code that follows the pattern for DWORD values above.
+ _ASSERTE(!CheckLookupOption(info, MayHavePerformanceDefault));
+
+ *outVal = result;
+ RETURN S_OK;
+}
+
+//
+// Check whether an option is specified (e.g. explicitly listed) in any location
+//
+// Arguments:
+// * name - the name field of the desired ConfigDWORDInfo/ConfigStringInfo
+//
+// static
+BOOL CLRConfig::IsConfigOptionSpecified(LPCWSTR name)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // Check config files
+ {
+ LPCWSTR result = NULL;
+
+ if (s_GetConfigValueCallback != NULL &&
+ SUCCEEDED(s_GetConfigValueCallback(name, &result, FALSE, FALSE)) &&
+ result != NULL)
+ {
+ return TRUE;
+ }
+ }
+
+ // Check REGUTIL, both with and without the COMPLUS_ prefix
+ {
+ LPWSTR result = NULL;
+
+ result = REGUTIL::GetConfigString_DontUse_(name, TRUE);
+ if (result != NULL)
+ {
+ FreeConfigString(result);
+ return TRUE;
+ }
+
+ result = REGUTIL::GetConfigString_DontUse_(name, FALSE);
+ if (result != NULL)
+ {
+ FreeConfigString(result);
+ return TRUE;
+ }
+
+ }
+
+ return FALSE;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Given an input string, returns a newly-allocated string equal to the input but with
+// leading and trailing whitespace trimmed off. If input is already trimmed, or if
+// trimming would result in an empty string, this function sets the output string to NULL
+//
+// Caller must free *pwszTrimmed if non-NULL
+//
+// Arguments:
+// * wszOrig - String to trim
+// * pwszTrimmed - [out]: On return, points to newly allocated, trimmed string (or
+// NULL)
+//
+// Return Value:
+// HRESULT indicating success or failure.
+//
+HRESULT CLRConfig::TrimWhiteSpace(LPCWSTR wszOrig, __deref_out_z LPWSTR * pwszTrimmed)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(wszOrig != NULL);
+ _ASSERTE(pwszTrimmed != NULL);
+
+ // In case we return early, set [out] to NULL by default
+ *pwszTrimmed = NULL;
+
+ // Get pointers into internal string that show where to do the trimming.
+ size_t cchOrig = wcslen(wszOrig);
+ if (!FitsIn<DWORD>(cchOrig))
+ return COR_E_OVERFLOW;
+ DWORD cchAfterTrim = (DWORD) cchOrig;
+ LPCWSTR wszAfterTrim = wszOrig;
+ ::TrimWhiteSpace(&wszAfterTrim, &cchAfterTrim);
+
+ // Is input string already trimmed? If so, save an allocation and just return.
+ if ((wszOrig == wszAfterTrim) && (cchOrig == cchAfterTrim))
+ {
+ // Yup, just return success
+ return S_OK;
+ }
+
+ if (cchAfterTrim == 0)
+ {
+ // After trimming, there's nothing left, so just return NULL
+ return S_OK;
+ }
+
+ // Create a new buffer to hold a copy of the trimmed string. Caller will be
+ // responsible for this buffer if we return it.
+ NewArrayHolder<WCHAR> wszTrimmedCopy(new (nothrow) WCHAR[cchAfterTrim + 1]);
+ if (wszTrimmedCopy == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ errno_t err = wcsncpy_s(wszTrimmedCopy, cchAfterTrim + 1, wszAfterTrim, cchAfterTrim);
+ if (err != 0)
+ {
+ return E_FAIL;
+ }
+
+ // Successfully made a copy of the trimmed string. Return it. Caller will be responsible for
+ // deleting it.
+ wszTrimmedCopy.SuppressRelease();
+ *pwszTrimmed = wszTrimmedCopy;
+ return S_OK;
+}
+
+
+//
+// Deallocation function for code:CLRConfig::FreeConfigString
+//
+void CLRConfig::FreeConfigString(__in_z LPWSTR str)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ delete [] str;
+}
+
+//
+// Register EEConfig's GetConfigValueCallback function so CLRConfig can look in config files.
+//
+//static
+void CLRConfig::RegisterGetConfigValueCallback(GetConfigValueFunction func)
+{
+ LIMITED_METHOD_CONTRACT;
+ s_GetConfigValueCallback = func;
+}
+
+//
+// Register PerformanceDefaults' LookupConfigValue so CLRConfig can support 'MayHavePerformanceDefault' values
+//
+//static
+void CLRConfig::RegisterGetPerformanceDefaultValueCallback(GetPerformanceDefaultValueFunction func)
+{
+ LIMITED_METHOD_CONTRACT;
+ s_GetPerformanceDefaultValueCallback = func;
+}
+
+#ifdef FEATURE_WIN_DB_APPCOMPAT
+void CLRConfig::RegisterWinDbQuirkApis(PFN_CptQuirkIsEnabled3 func1, PFN_CptQuirkGetData2 func2)
+{
+ LIMITED_METHOD_CONTRACT;
+ s_IsQuirkEnabledCallback = func1;
+ s_GetQuirkValueCallback = func2;
+}
+#endif // FEATURE_WIN_DB_APPCOMPAT
+
+//
+// Helper method to translate LookupOptions to REGUTIL::CORConfigLevel.
+//
+//static
+REGUTIL::CORConfigLevel CLRConfig::GetConfigLevel(LookupOptions options)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ REGUTIL::CORConfigLevel level = (REGUTIL::CORConfigLevel) 0;
+
+ if(CheckLookupOption(options, IgnoreEnv) == FALSE)
+ level = static_cast<REGUTIL::CORConfigLevel>(level | REGUTIL::COR_CONFIG_ENV);
+
+ if(CheckLookupOption(options, IgnoreHKCU) == FALSE)
+ level = static_cast<REGUTIL::CORConfigLevel>(level | REGUTIL::COR_CONFIG_USER);
+
+ if(CheckLookupOption(options, IgnoreHKLM) == FALSE)
+ level = static_cast<REGUTIL::CORConfigLevel>(level | REGUTIL::COR_CONFIG_MACHINE);
+
+ return level;
+}