3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 using Microsoft
.Win32
.SafeHandles
;
10 using System
.Collections
.Generic
;
11 using System
.Diagnostics
;
12 using System
.Security
;
16 internal static partial class AppContextDefaultValues
19 /// This method is going to parse the <paramref name="overrides"/> parameter and set the values corresponding to them
20 /// in the AppContext object
22 [SecuritySafeCritical
]
23 static partial void PopulateOverrideValuesPartial()
25 // Retrieve the value from EE config.
26 string overrides
= System
.Runtime
.Versioning
.CompatibilitySwitch
.GetAppContextOverridesInternalCall();
28 // If we have no override values, do nothing.
29 if (string.IsNullOrEmpty(overrides
))
32 bool encounteredEquals
= false, encounteredCharsInKey
= false, encounteredCharsInValue
= false;
33 int previousSemicolonPos
= -1, firstEqualsPos
= -1;
35 // Iterate over the string one character at a time until we reach the end of the string.
36 for (int currentPos
= 0; currentPos
<= overrides
.Length
; currentPos
++)
38 // If the current position is either ';' or 'end-of-string' then we potentially have a key=value pair
39 if (currentPos
== overrides
.Length
|| overrides
[currentPos
] == ';')
41 // We only have a key=value pair if we encountered an equals, characters in the key and in the value
42 // portion of the pair.
43 if (encounteredEquals
&& encounteredCharsInKey
&& encounteredCharsInValue
)
45 // We compute the indexes in the string for key and value
46 int firstCharOfKey
= previousSemicolonPos
+ 1; //+1 because we don't take the ';' char
47 int lenghtOfKey
= firstEqualsPos
- previousSemicolonPos
- 1; //-1 because we don't take the '=' char
48 string name
= overrides
.Substring(firstCharOfKey
, lenghtOfKey
);
50 int firstCharOfValue
= firstEqualsPos
+ 1; // +1 because we don't count the '='
51 int lengthOfValue
= currentPos
- firstEqualsPos
- 1; // -1 because we don't count the '='
52 string value = overrides
.Substring(firstCharOfValue
, lengthOfValue
);
54 // apply the value only if it parses as a boolean
56 if (bool.TryParse(value, out switchValue
))
58 // If multiple switches have the same name, the last value that we find will win.
59 AppContext
.DefineSwitchOverride(name
, switchValue
);
62 previousSemicolonPos
= currentPos
;
64 // We need to reset these flags once we encounter a ';'
65 encounteredCharsInKey
= encounteredCharsInValue
= encounteredEquals
= false;
67 else if (overrides
[currentPos
] == '=')
69 // if the current character is '=' then we should flag it and remember it
70 if (!encounteredEquals
)
72 encounteredEquals
= true;
73 firstEqualsPos
= currentPos
;
78 // We need to know if the key or value contain any characters (other than ';' and '=');
79 if (encounteredEquals
)
81 encounteredCharsInValue
= true;
85 encounteredCharsInKey
= true;
91 // Note -- partial methods cannot return a value so we use refs to return information
92 [SecuritySafeCritical
]
93 static partial void TryGetSwitchOverridePartial(string switchName
, ref bool overrideFound
, ref bool overrideValue
)
95 string valueFromConfig
= null;
97 overrideFound
= false;
99 // Read the value from the registry if we can (ie. the key exists)
100 if (s_errorReadingRegistry
!= true)
102 // try to read it from the registry key and return null if the switch name is not found
103 valueFromConfig
= GetSwitchValueFromRegistry(switchName
);
106 // Note: valueFromConfig will be null only if the key is not found.
107 // Read the value from the Shim database.
108 if (valueFromConfig
== null)
110 // We are only going to check the Shim Database for an override in this case
111 valueFromConfig
= System
.Runtime
.Versioning
.CompatibilitySwitch
.GetValue(switchName
);
114 if (valueFromConfig
!= null && bool.TryParse(valueFromConfig
, out boolFromConfig
))
116 // If we found a valid override value, we need to let the caller know that.
117 overrideValue
= boolFromConfig
;
118 overrideFound
= true;
122 private volatile static bool s_errorReadingRegistry
;
123 [SecuritySafeCritical
]
124 private static string GetSwitchValueFromRegistry(string switchName
)
127 // We are using P/Invokes directly instead of using the RegistryKey class to avoid pulling in the
128 // globalization stack that is required by RegistryKey.
130 const string REG_KEY_APPCONTEXT
= @"SOFTWARE\Microsoft\.NETFramework\AppContext";
133 using (SafeRegistryHandle hklm
= new SafeRegistryHandle((IntPtr
)RegistryHive
.LocalMachine
, true))
135 SafeRegistryHandle hkey
= null;
137 if (Win32Native
.RegOpenKeyEx(hklm
, REG_KEY_APPCONTEXT
, 0, Win32Native
.KEY_READ
, out hkey
) == 0)
139 int size
= 6 * sizeof(char); // "false".Length+1 * sizeof (char) as the API expects byte count and not char count.
141 System
.Text
.StringBuilder keyBuffer
= new System
.Text
.StringBuilder((int)size
);
142 if (Win32Native
.RegQueryValueEx(hkey
, switchName
, null, ref type
, keyBuffer
, ref size
) == 0)
144 return keyBuffer
.ToString();
149 // If we could not open the AppContext key, don't try it again.
150 s_errorReadingRegistry
= true;
156 // If there was an error, flag it so that we don't try this again.
157 s_errorReadingRegistry
= true;