1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | //***************************************************************************** |
5 | // Util_NoDependencies.cpp |
6 | // |
7 | |
8 | // |
9 | // This contains a bunch of C++ utility classes needed also for UtilCode without dependencies |
10 | // (standalone version without CLR/clr.dll/mscoree.dll dependencies). |
11 | // |
12 | //***************************************************************************** |
13 | |
14 | #include "stdafx.h" |
15 | #include "utilcode.h" |
16 | #include "ex.h" |
17 | |
18 | #if !defined(FEATURE_UTILCODE_NO_DEPENDENCIES) || defined(_DEBUG) |
19 | |
20 | RunningOnStatusEnum gRunningOnStatus = RUNNING_ON_STATUS_UNINITED; |
21 | |
22 | #define NON_SUPPORTED_PLATFORM_MSGBOX_TITLE W("Platform not supported") |
23 | #define NON_SUPPORTED_PLATFORM_MSGBOX_TEXT W("The minimum supported platform is Windows 7") |
24 | #define NON_SUPPORTED_PLATFORM_TERMINATE_ERROR_CODE 0xBAD1BAD1 |
25 | |
26 | //***************************************************************************** |
27 | // One time initialization of the OS version |
28 | //***************************************************************************** |
29 | void InitRunningOnVersionStatus () |
30 | { |
31 | #ifndef FEATURE_PAL |
32 | STATIC_CONTRACT_NOTHROW; |
33 | STATIC_CONTRACT_GC_NOTRIGGER; |
34 | STATIC_CONTRACT_CANNOT_TAKE_LOCK; |
35 | STATIC_CONTRACT_SO_TOLERANT; |
36 | |
37 | BOOL fSupportedPlatform = FALSE; |
38 | OSVERSIONINFOEX sVer; |
39 | DWORDLONG dwlConditionMask; |
40 | |
41 | ZeroMemory(&sVer, sizeof(OSVERSIONINFOEX)); |
42 | sVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); |
43 | |
44 | sVer.dwMajorVersion = 6; |
45 | sVer.dwMinorVersion = 2; |
46 | sVer.dwPlatformId = VER_PLATFORM_WIN32_NT; |
47 | |
48 | |
49 | dwlConditionMask = 0; |
50 | dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL); |
51 | dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); |
52 | dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); |
53 | |
54 | if(VerifyVersionInfo(&sVer, VER_MAJORVERSION | VER_PLATFORMID | VER_MINORVERSION, dwlConditionMask)) |
55 | { |
56 | gRunningOnStatus = RUNNING_ON_WIN8; |
57 | fSupportedPlatform = TRUE; |
58 | goto CHECK_SUPPORTED; |
59 | } |
60 | |
61 | |
62 | ZeroMemory(&sVer, sizeof(OSVERSIONINFOEX)); |
63 | sVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); |
64 | |
65 | sVer.dwMajorVersion = 6; |
66 | sVer.dwMinorVersion = 1; |
67 | sVer.dwPlatformId = VER_PLATFORM_WIN32_NT; |
68 | |
69 | |
70 | dwlConditionMask = 0; |
71 | dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL); |
72 | dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); |
73 | dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); |
74 | |
75 | if(VerifyVersionInfo(&sVer, VER_MAJORVERSION | VER_PLATFORMID | VER_MINORVERSION, dwlConditionMask)) |
76 | { |
77 | gRunningOnStatus = RUNNING_ON_WIN7; |
78 | fSupportedPlatform = TRUE; |
79 | goto CHECK_SUPPORTED; |
80 | } |
81 | |
82 | CHECK_SUPPORTED: |
83 | |
84 | if (!fSupportedPlatform) |
85 | { |
86 | // The current platform isn't supported. Display a message box to this effect and exit. |
87 | // Note that this should never happen since the .NET Fx setup should not install on |
88 | // non supported platforms (which is why the message box text isn't localized). |
89 | UtilMessageBoxCatastrophicNonLocalized(NON_SUPPORTED_PLATFORM_MSGBOX_TITLE, NON_SUPPORTED_PLATFORM_MSGBOX_TEXT, MB_OK | MB_ICONERROR, TRUE); |
90 | TerminateProcess(GetCurrentProcess(), NON_SUPPORTED_PLATFORM_TERMINATE_ERROR_CODE); |
91 | } |
92 | #endif // FEATURE_PAL |
93 | } // InitRunningOnVersionStatus |
94 | |
95 | #ifndef _WIN64 |
96 | //------------------------------------------------------------------------------ |
97 | // Returns TRUE if we are running on a 64-bit OS in WoW, FALSE otherwise. |
98 | BOOL RunningInWow64() |
99 | { |
100 | #ifdef PLATFORM_UNIX |
101 | return FALSE; |
102 | #else |
103 | static int s_Wow64Process; |
104 | |
105 | if (s_Wow64Process == 0) |
106 | { |
107 | BOOL fWow64Process = FALSE; |
108 | |
109 | if (!IsWow64Process(GetCurrentProcess(), &fWow64Process)) |
110 | fWow64Process = FALSE; |
111 | |
112 | s_Wow64Process = fWow64Process ? 1 : -1; |
113 | } |
114 | |
115 | return (s_Wow64Process == 1) ? TRUE : FALSE; |
116 | #endif |
117 | } |
118 | #endif |
119 | |
120 | #ifndef FEATURE_PAL |
121 | //------------------------------------------------------------------------------ |
122 | // |
123 | // GetRegistryLongValue - Reads a configuration LONG value from the registry. |
124 | // |
125 | // Parameters |
126 | // hKeyParent -- Parent key |
127 | // szKey -- key to open |
128 | // szName -- name of the value |
129 | // pValue -- put value here, if found |
130 | // fReadNonVirtualizedKey -- whether to read 64-bit hive on WOW64 |
131 | // |
132 | // Returns |
133 | // TRUE -- If the value was found and read |
134 | // FALSE -- The value was not found, could not be read, or was not DWORD |
135 | // |
136 | // Exceptions |
137 | // None |
138 | //------------------------------------------------------------------------------ |
139 | BOOL GetRegistryLongValue(HKEY hKeyParent, |
140 | LPCWSTR szKey, |
141 | LPCWSTR szName, |
142 | long *pValue, |
143 | BOOL fReadNonVirtualizedKey) |
144 | { |
145 | CONTRACTL |
146 | { |
147 | NOTHROW; |
148 | GC_NOTRIGGER; |
149 | } |
150 | CONTRACTL_END; |
151 | |
152 | DWORD ret; // Return value from registry operation. |
153 | HKEYHolder hkey; // Registry key. |
154 | long iValue; // The value to read. |
155 | DWORD iType; // Type of value to get. |
156 | DWORD iSize; // Size of buffer. |
157 | REGSAM samDesired = KEY_READ; // Desired access rights to the key |
158 | |
159 | if (fReadNonVirtualizedKey) |
160 | { |
161 | if (RunningInWow64()) |
162 | { |
163 | samDesired |= KEY_WOW64_64KEY; |
164 | } |
165 | } |
166 | |
167 | ret = WszRegOpenKeyEx(hKeyParent, szKey, 0, samDesired, &hkey); |
168 | |
169 | // If we opened the key, see if there is a value. |
170 | if (ret == ERROR_SUCCESS) |
171 | { |
172 | iType = REG_DWORD; |
173 | iSize = sizeof(long); |
174 | ret = WszRegQueryValueEx(hkey, szName, NULL, &iType, reinterpret_cast<BYTE*>(&iValue), &iSize); |
175 | |
176 | if (ret == ERROR_SUCCESS && iType == REG_DWORD && iSize == sizeof(long)) |
177 | { // We successfully read a DWORD value. |
178 | *pValue = iValue; |
179 | return TRUE; |
180 | } |
181 | } |
182 | |
183 | return FALSE; |
184 | } // GetRegistryLongValue |
185 | |
186 | //---------------------------------------------------------------------------- |
187 | // |
188 | // GetCurrentModuleFileName - Retrieve the current module's filename |
189 | // |
190 | // Arguments: |
191 | // pBuffer - output string buffer |
192 | // |
193 | // Return Value: |
194 | // S_OK on success, else detailed error code. |
195 | // |
196 | // Note: |
197 | // |
198 | //---------------------------------------------------------------------------- |
199 | HRESULT GetCurrentModuleFileName(SString& pBuffer) |
200 | { |
201 | LIMITED_METHOD_CONTRACT; |
202 | |
203 | |
204 | DWORD ret = WszGetModuleFileName(NULL, pBuffer); |
205 | |
206 | if (ret == 0) |
207 | { |
208 | return E_UNEXPECTED; |
209 | } |
210 | |
211 | |
212 | return S_OK; |
213 | } |
214 | |
215 | //---------------------------------------------------------------------------- |
216 | // |
217 | // IsCurrentModuleFileNameInAutoExclusionList - decide if the current module's filename |
218 | // is in the AutoExclusionList list |
219 | // |
220 | // Arguments: |
221 | // None |
222 | // |
223 | // Return Value: |
224 | // TRUE or FALSE |
225 | // |
226 | // Note: |
227 | // This function cannot be used in out of process scenarios like DAC because it |
228 | // looks at current module's filename. In OOP we want to use target process's |
229 | // module's filename. |
230 | // |
231 | //---------------------------------------------------------------------------- |
232 | BOOL IsCurrentModuleFileNameInAutoExclusionList() |
233 | { |
234 | CONTRACTL |
235 | { |
236 | NOTHROW; |
237 | GC_NOTRIGGER; |
238 | } |
239 | CONTRACTL_END; |
240 | |
241 | HKEYHolder hKeyHolder; |
242 | |
243 | // Look for "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList" |
244 | DWORD ret = WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, kUnmanagedDebuggerAutoExclusionListKey, 0, KEY_READ, &hKeyHolder); |
245 | |
246 | if (ret != ERROR_SUCCESS) |
247 | { |
248 | // there's not even an AutoExclusionList hive |
249 | return FALSE; |
250 | } |
251 | |
252 | PathString wszAppName; |
253 | |
254 | // Get the appname to look up in the exclusion or inclusion list. |
255 | if (GetCurrentModuleFileName(wszAppName) != S_OK) |
256 | { |
257 | // Assume it is not on the exclusion list if we cannot find the module's filename. |
258 | return FALSE; |
259 | } |
260 | |
261 | // Look in AutoExclusionList key for appName get the size of any value stored there. |
262 | DWORD value, valueType, valueSize = sizeof(value); |
263 | ret = WszRegQueryValueEx(hKeyHolder, wszAppName, 0, &valueType, reinterpret_cast<BYTE*>(&value), &valueSize); |
264 | if ((ret == ERROR_SUCCESS) && (valueType == REG_DWORD) && (value == 1)) |
265 | { |
266 | return TRUE; |
267 | } |
268 | |
269 | return FALSE; |
270 | } // IsCurrentModuleFileNameInAutoExclusionList |
271 | |
272 | //***************************************************************************** |
273 | // Retrieve information regarding what registered default debugger |
274 | //***************************************************************************** |
275 | void GetDebuggerSettingInfo(SString &ssDebuggerString, BOOL *pfAuto) |
276 | { |
277 | CONTRACTL |
278 | { |
279 | NOTHROW; |
280 | GC_NOTRIGGER; |
281 | } |
282 | CONTRACTL_END; |
283 | |
284 | EX_TRY |
285 | { |
286 | DWORD cchDebuggerString = MAX_LONGPATH; |
287 | INDEBUG(DWORD cchOldDebuggerString = cchDebuggerString); |
288 | |
289 | WCHAR * buf = ssDebuggerString.OpenUnicodeBuffer(cchDebuggerString); |
290 | HRESULT hr = GetDebuggerSettingInfoWorker(buf, &cchDebuggerString, pfAuto); |
291 | ssDebuggerString.CloseBuffer(cchDebuggerString); |
292 | |
293 | while (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) |
294 | { |
295 | _ASSERTE(cchDebuggerString > cchOldDebuggerString); |
296 | INDEBUG(cchOldDebuggerString = cchDebuggerString); |
297 | |
298 | buf = ssDebuggerString.OpenUnicodeBuffer(cchDebuggerString); |
299 | hr = GetDebuggerSettingInfoWorker(buf, &cchDebuggerString, pfAuto); |
300 | ssDebuggerString.CloseBuffer(cchDebuggerString); |
301 | } |
302 | |
303 | if (*ssDebuggerString.GetUnicode() == W('\0')) |
304 | { |
305 | ssDebuggerString.Clear(); |
306 | } |
307 | |
308 | if (FAILED(hr)) |
309 | { |
310 | ssDebuggerString.Clear(); |
311 | if (pfAuto) |
312 | { |
313 | *pfAuto = FALSE; |
314 | } |
315 | } |
316 | } |
317 | EX_CATCH |
318 | { |
319 | ssDebuggerString.Clear(); |
320 | if (pfAuto) |
321 | { |
322 | *pfAuto = FALSE; |
323 | } |
324 | } |
325 | EX_END_CATCH(SwallowAllExceptions); |
326 | } // GetDebuggerSettingInfo |
327 | |
328 | //--------------------------------------------------------------------------------------- |
329 | // |
330 | // GetDebuggerSettingInfoWorker - retrieve information regarding what registered default debugger |
331 | // |
332 | // Arguments: |
333 | // * wszDebuggerString - [out] the string buffer to store the registered debugger launch |
334 | // string |
335 | // * pcchDebuggerString - [in, out] the size of string buffer in characters |
336 | // * pfAuto - [in] the flag to indicate whether the debugger neeeds to be launched |
337 | // automatically |
338 | // |
339 | // Return Value: |
340 | // HRESULT indicating success or failure. |
341 | // |
342 | // Notes: |
343 | // * wszDebuggerString can be NULL. When wszDebuggerString is NULL, pcchDebuggerString should |
344 | // * point to a DWORD of zero. pcchDebuggerString cannot be NULL, and the DWORD pointed by |
345 | // * pcchDebuggerString will store the used or required string buffer size in characters. |
346 | HRESULT GetDebuggerSettingInfoWorker(__out_ecount_part_opt(*pcchDebuggerString, *pcchDebuggerString) LPWSTR wszDebuggerString, DWORD * pcchDebuggerString, BOOL * pfAuto) |
347 | { |
348 | CONTRACTL |
349 | { |
350 | NOTHROW; |
351 | GC_NOTRIGGER; |
352 | PRECONDITION(pcchDebuggerString != NULL); |
353 | } |
354 | CONTRACTL_END; |
355 | |
356 | if ((pcchDebuggerString == NULL) || ((wszDebuggerString == NULL) && (*pcchDebuggerString != 0))) |
357 | { |
358 | return E_INVALIDARG; |
359 | } |
360 | |
361 | // Initialize the output values before we start. |
362 | if ((wszDebuggerString != NULL) && (*pcchDebuggerString > 0)) |
363 | { |
364 | *wszDebuggerString = W('\0'); |
365 | } |
366 | |
367 | if (pfAuto != NULL) |
368 | { |
369 | *pfAuto = FALSE; |
370 | } |
371 | |
372 | HKEYHolder hKeyHolder; |
373 | |
374 | // Look for "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" |
375 | DWORD ret = WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, kUnmanagedDebuggerKey, 0, KEY_READ, &hKeyHolder); |
376 | |
377 | if (ret != ERROR_SUCCESS) |
378 | { // Wow, there's not even an AeDebug hive, so no native debugger, no auto. |
379 | return S_OK; |
380 | } |
381 | |
382 | // Look in AeDebug key for "Debugger"; get the size of any value stored there. |
383 | DWORD valueType, valueSize = 0; |
384 | ret = WszRegQueryValueEx(hKeyHolder, kUnmanagedDebuggerValue, 0, &valueType, 0, &valueSize); |
385 | |
386 | _ASSERTE(pcchDebuggerString != NULL); |
387 | if ((wszDebuggerString == NULL) || (*pcchDebuggerString < valueSize / sizeof(WCHAR))) |
388 | { |
389 | *pcchDebuggerString = valueSize / sizeof(WCHAR) + 1; |
390 | return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); |
391 | } |
392 | |
393 | *pcchDebuggerString = valueSize / sizeof(WCHAR); |
394 | |
395 | // The size of an empty string with the null terminator is 2. |
396 | BOOL fIsDebuggerStringEmptry = valueSize <= 2 ? TRUE : FALSE; |
397 | |
398 | if ((ret != ERROR_SUCCESS) || (valueType != REG_SZ) || fIsDebuggerStringEmptry) |
399 | { |
400 | return S_OK; |
401 | } |
402 | |
403 | _ASSERTE(wszDebuggerString != NULL); |
404 | ret = WszRegQueryValueEx(hKeyHolder, kUnmanagedDebuggerValue, NULL, NULL, reinterpret_cast< LPBYTE >(wszDebuggerString), &valueSize); |
405 | if (ret != ERROR_SUCCESS) |
406 | { |
407 | *wszDebuggerString = W('\0'); |
408 | return S_OK; |
409 | } |
410 | |
411 | // The callers are in nothrow scope, so we must swallow exceptions and reset the output parameters to the |
412 | // default values if exceptions like OOM ever happen. |
413 | EX_TRY |
414 | { |
415 | if (pfAuto != NULL) |
416 | { |
417 | BOOL fAuto = FALSE; |
418 | |
419 | // Get the appname to look up in DebugApplications key. |
420 | PathString wzAppName; |
421 | long iValue; |
422 | |
423 | // Check DebugApplications setting |
424 | if ((SUCCEEDED(GetCurrentModuleFileName(wzAppName))) && |
425 | ( |
426 | GetRegistryLongValue(HKEY_LOCAL_MACHINE, kDebugApplicationsPoliciesKey, wzAppName, &iValue, TRUE) || |
427 | GetRegistryLongValue(HKEY_LOCAL_MACHINE, kDebugApplicationsKey, wzAppName, &iValue, TRUE) || |
428 | GetRegistryLongValue(HKEY_CURRENT_USER, kDebugApplicationsPoliciesKey, wzAppName, &iValue, TRUE) || |
429 | GetRegistryLongValue(HKEY_CURRENT_USER, kDebugApplicationsKey, wzAppName, &iValue, TRUE) |
430 | ) && |
431 | (iValue == 1)) |
432 | { |
433 | fAuto = TRUE; |
434 | } |
435 | else |
436 | { |
437 | // Look in AeDebug key for "Auto"; get the size of any value stored there. |
438 | ret = WszRegQueryValueEx(hKeyHolder, kUnmanagedDebuggerAutoValue, 0, &valueType, 0, &valueSize); |
439 | if ((ret == ERROR_SUCCESS) && (valueType == REG_SZ) && (valueSize / sizeof(WCHAR) < MAX_LONGPATH)) |
440 | { |
441 | WCHAR wzAutoKey[MAX_LONGPATH]; |
442 | valueSize = NumItems(wzAutoKey) * sizeof(WCHAR); |
443 | WszRegQueryValueEx(hKeyHolder, kUnmanagedDebuggerAutoValue, NULL, NULL, reinterpret_cast< LPBYTE >(wzAutoKey), &valueSize); |
444 | |
445 | // The OS's behavior is to consider Auto to be FALSE unless the first character is set |
446 | // to 1. They don't take into consideration the following characters. Also if the value |
447 | // isn't present they assume an Auto value of FALSE. |
448 | if ((wzAutoKey[0] == W('1')) && !IsCurrentModuleFileNameInAutoExclusionList()) |
449 | { |
450 | fAuto = TRUE; |
451 | } |
452 | } |
453 | } |
454 | |
455 | *pfAuto = fAuto; |
456 | } |
457 | } |
458 | EX_CATCH |
459 | { |
460 | if ((wszDebuggerString != NULL) && (*pcchDebuggerString > 0)) |
461 | { |
462 | *wszDebuggerString = W('\0'); |
463 | } |
464 | |
465 | if (pfAuto != NULL) |
466 | { |
467 | *pfAuto = FALSE; |
468 | } |
469 | } |
470 | EX_END_CATCH(SwallowAllExceptions); |
471 | |
472 | return S_OK; |
473 | } // GetDebuggerSettingInfoWorker |
474 | #endif // FEATURE_PAL |
475 | |
476 | #endif //!defined(FEATURE_UTILCODE_NO_DEPENDENCIES) || defined(_DEBUG) |
477 | |
478 | //***************************************************************************** |
479 | // Convert hex value into a wide string of hex digits |
480 | //***************************************************************************** |
481 | HRESULT GetStr( |
482 | DWORD hHexNum, |
483 | __out_ecount((cbHexNum * 2)) LPWSTR szHexNum, |
484 | DWORD cbHexNum) |
485 | { |
486 | CONTRACTL |
487 | { |
488 | NOTHROW; |
489 | } |
490 | CONTRACTL_END; |
491 | |
492 | _ASSERTE (szHexNum); |
493 | cbHexNum *= 2; // each nibble is a char |
494 | while (cbHexNum != 0) |
495 | { |
496 | DWORD thisHexDigit = hHexNum % 16; |
497 | hHexNum /= 16; |
498 | cbHexNum--; |
499 | if (thisHexDigit < 10) |
500 | { |
501 | *(szHexNum+cbHexNum) = (BYTE)(thisHexDigit + W('0')); |
502 | } |
503 | else |
504 | { |
505 | *(szHexNum+cbHexNum) = (BYTE)(thisHexDigit - 10 + W('A')); |
506 | } |
507 | } |
508 | return S_OK; |
509 | } |
510 | |
511 | //***************************************************************************** |
512 | // Convert a GUID into a pointer to a Wide char string |
513 | //***************************************************************************** |
514 | int |
515 | GuidToLPWSTR( |
516 | GUID Guid, // The GUID to convert. |
517 | __out_ecount(cchGuid) LPWSTR szGuid, // String into which the GUID is stored |
518 | DWORD cchGuid) // Count in wchars |
519 | { |
520 | CONTRACTL |
521 | { |
522 | NOTHROW; |
523 | } |
524 | CONTRACTL_END; |
525 | |
526 | int i; |
527 | |
528 | // successive fields break the GUID into the form DWORD-WORD-WORD-WORD-WORD.DWORD |
529 | // covering the 128-bit GUID. The string includes enclosing braces, which are an OLE convention. |
530 | |
531 | if (cchGuid < 39) // 38 chars + 1 null terminating. |
532 | return 0; |
533 | |
534 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
535 | // ^ |
536 | szGuid[0] = W('{'); |
537 | |
538 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
539 | // ^^^^^^^^ |
540 | if (FAILED (GetStr(Guid.Data1, szGuid+1 , 4))) return 0; |
541 | |
542 | szGuid[9] = W('-'); |
543 | |
544 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
545 | // ^^^^ |
546 | if (FAILED (GetStr(Guid.Data2, szGuid+10, 2))) return 0; |
547 | |
548 | szGuid[14] = W('-'); |
549 | |
550 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
551 | // ^^^^ |
552 | if (FAILED (GetStr(Guid.Data3, szGuid+15, 2))) return 0; |
553 | |
554 | szGuid[19] = W('-'); |
555 | |
556 | // Get the last two fields (which are byte arrays). |
557 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
558 | // ^^^^ |
559 | for (i=0; i < 2; ++i) |
560 | if (FAILED(GetStr(Guid.Data4[i], szGuid + 20 + (i * 2), 1))) |
561 | return (0); |
562 | |
563 | szGuid[24] = W('-'); |
564 | |
565 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
566 | // ^^^^^^^^^^^^ |
567 | for (i=0; i < 6; ++i) |
568 | if (FAILED(GetStr(Guid.Data4[i+2], szGuid + 25 + (i * 2), 1))) |
569 | return (0); |
570 | |
571 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
572 | // ^ |
573 | szGuid[37] = W('}'); |
574 | szGuid[38] = W('\0'); |
575 | |
576 | return 39; |
577 | } // GuidToLPWSTR |
578 | |
579 | //***************************************************************************** |
580 | // Convert wide string of (at most eight) hex digits into a hex value |
581 | //***************************************************************************** |
582 | HRESULT GetHex( |
583 | DWORD * phHexNum, |
584 | __in_ecount((cbHexNum * 2)) LPCWSTR szHexNum, |
585 | DWORD cbHexNum) |
586 | { |
587 | CONTRACTL |
588 | { |
589 | NOTHROW; |
590 | } |
591 | CONTRACTL_END; |
592 | |
593 | _ASSERTE (szHexNum && phHexNum); |
594 | _ASSERTE(cbHexNum == 1 || cbHexNum == 2 || cbHexNum == 4); |
595 | |
596 | cbHexNum *= 2; // each nibble is a char |
597 | DWORD val = 0; |
598 | for (DWORD i = 0; i < cbHexNum; ++i) |
599 | { |
600 | DWORD nibble = 0; |
601 | if (szHexNum[i] >= W('0') && szHexNum[i] <= W('9')) |
602 | { |
603 | nibble = szHexNum[i] - '0'; |
604 | } |
605 | else if (szHexNum[i] >= W('A') && szHexNum[i] <= W('F')) |
606 | { |
607 | nibble = 10 + szHexNum[i] - 'A'; |
608 | } |
609 | else if (szHexNum[i] >= W('a') && szHexNum[i] <= W('f')) |
610 | { |
611 | nibble = 10 + szHexNum[i] - 'a'; |
612 | } |
613 | else |
614 | { |
615 | return E_FAIL; |
616 | } |
617 | val = (val << 4) + nibble; |
618 | } |
619 | *phHexNum = val; |
620 | return S_OK; |
621 | } |
622 | |
623 | //***************************************************************************** |
624 | // Parse a Wide char string into a GUID |
625 | //***************************************************************************** |
626 | BOOL |
627 | LPWSTRToGuid( |
628 | GUID * Guid, // [OUT] The GUID to fill in |
629 | __in_ecount(cchGuid) LPCWSTR szGuid, // [IN] String to parse |
630 | DWORD cchGuid) // [IN] Count in wchars in string |
631 | { |
632 | CONTRACTL |
633 | { |
634 | NOTHROW; |
635 | } |
636 | CONTRACTL_END; |
637 | |
638 | int i; |
639 | DWORD dw; |
640 | |
641 | // successive fields break the GUID into the form DWORD-WORD-WORD-WORD-WORD.DWORD |
642 | // covering the 128-bit GUID. The string includes enclosing braces, which are an OLE convention. |
643 | |
644 | if (cchGuid < 38) // 38 chars + 1 null terminating. |
645 | return FALSE; |
646 | |
647 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
648 | // ^ |
649 | if (szGuid[0] != W('{')) return FALSE; |
650 | |
651 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
652 | // ^^^^^^^^ |
653 | if (FAILED (GetHex(&dw, szGuid+1 , 4))) return FALSE; |
654 | Guid->Data1 = dw; |
655 | |
656 | if (szGuid[9] != W('-')) return FALSE; |
657 | |
658 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
659 | // ^^^^ |
660 | if (FAILED (GetHex(&dw, szGuid+10, 2))) return FALSE; |
661 | Guid->Data2 = (WORD)dw; |
662 | |
663 | if (szGuid[14] != W('-')) return FALSE; |
664 | |
665 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
666 | // ^^^^ |
667 | if (FAILED (GetHex(&dw, szGuid+15, 2))) return FALSE; |
668 | Guid->Data3 = (WORD)dw; |
669 | |
670 | if (szGuid[19] != W('-')) return FALSE; |
671 | |
672 | // Get the last two fields (which are byte arrays). |
673 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
674 | // ^^^^ |
675 | for (i=0; i < 2; ++i) |
676 | { |
677 | if (FAILED(GetHex(&dw, szGuid + 20 + (i * 2), 1))) return FALSE; |
678 | Guid->Data4[i] = (BYTE)dw; |
679 | } |
680 | |
681 | if (szGuid[24] != W('-')) return FALSE; |
682 | |
683 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
684 | // ^^^^^^^^^^^^ |
685 | for (i=0; i < 6; ++i) |
686 | { |
687 | if (FAILED(GetHex(&dw, szGuid + 25 + (i * 2), 1))) return FALSE; |
688 | Guid->Data4[i+2] = (BYTE)dw; |
689 | } |
690 | |
691 | // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} |
692 | // ^ |
693 | if (szGuid[37] != W('}')) return FALSE; |
694 | |
695 | return TRUE; |
696 | } // GuidToLPWSTR |
697 | |
698 | |
699 | #ifdef _DEBUG |
700 | // Always write regardless of registry. |
701 | void _cdecl DbgWriteEx(LPCTSTR szFmt, ...) |
702 | { |
703 | CONTRACTL |
704 | { |
705 | NOTHROW; |
706 | } |
707 | CONTRACTL_END; |
708 | |
709 | WCHAR rcBuff[1024]; |
710 | va_list marker; |
711 | |
712 | va_start(marker, szFmt); |
713 | _vsnwprintf_s(rcBuff, _countof(rcBuff), _TRUNCATE, szFmt, marker); |
714 | va_end(marker); |
715 | WszOutputDebugString(rcBuff); |
716 | } |
717 | #endif //_DEBUG |
718 | |
719 | /**************************************************************************/ |
720 | void ConfigDWORD::init(const CLRConfig::ConfigDWORDInfo & info) |
721 | { |
722 | CONTRACTL |
723 | { |
724 | NOTHROW; |
725 | } |
726 | CONTRACTL_END; |
727 | |
728 | // make sure that the memory was zero initialized |
729 | _ASSERTE(m_inited == 0 || m_inited == 1); |
730 | |
731 | m_value = CLRConfig::GetConfigValue(info); |
732 | m_inited = 1; |
733 | } |
734 | |
735 | //--------------------------------------------------------------------------------------- |
736 | // |
737 | // Takes a const input string, and returns the start & size of the substring that has all |
738 | // leading and trailing whitespace removed. The original string is not modified. |
739 | // |
740 | // Arguments: |
741 | // * pwsz - [in] points to const string we want to trim; [out] points to beginning |
742 | // of trimmed substring of input string |
743 | // * pcch - [in] Points to length in chars of input string (not counting null |
744 | // terminator); [out] Points to length in chars of trimmed substring (not |
745 | // counting null terminator) |
746 | // |
747 | void TrimWhiteSpace(__deref_inout_ecount(*pcch) LPCWSTR *pwsz, __inout LPDWORD pcch) |
748 | { |
749 | LIMITED_METHOD_DAC_CONTRACT; |
750 | |
751 | _ASSERTE (pwsz != NULL); |
752 | _ASSERTE (*pwsz != NULL); |
753 | _ASSERTE (pcch != NULL); |
754 | |
755 | DWORD cch = *pcch; |
756 | LPCWSTR wszBeginning = *pwsz; |
757 | LPCWSTR wszEnd = wszBeginning + (cch - 1); |
758 | |
759 | while ((cch != 0) && iswspace(*wszBeginning)) |
760 | { |
761 | wszBeginning++; |
762 | cch--; |
763 | } |
764 | |
765 | while ((cch != 0) && iswspace(*wszEnd)) |
766 | { |
767 | wszEnd--; |
768 | cch--; |
769 | } |
770 | |
771 | *pwsz = wszBeginning; |
772 | *pcch = cch; |
773 | } // TrimWhiteSpace |
774 | |
775 | BOOL ThreadWillCreateGuardPage(SIZE_T sizeReservedStack, SIZE_T sizeCommitedStack) |
776 | { |
777 | // We need to make sure there will be a reserved but never committed page at the end |
778 | // of the stack. We do here the check NT does when it creates the user stack to decide |
779 | // if there is going to be a guard page. However, that is not enough, as if we only |
780 | // have a guard page, we have nothing to protect us from going pass it. Well, in |
781 | // fact, there is something that we will protect you, there are certain places |
782 | // (RTLUnwind) in NT that will check that the current frame is within stack limits. |
783 | // If we are not it will bomb out. We will also bomb out if we touch the hard guard |
784 | // page. |
785 | // |
786 | // For situation B, teb->StackLimit is at the beggining of the user stack (ie |
787 | // before updating StackLimit it checks if it was able to create a new guard page, |
788 | // in this case, it can't), which makes the check fail in RtlUnwind. |
789 | // |
790 | // Situation A [ Hard guard page | Guard page | user stack] |
791 | // |
792 | // Situation B [ Guard page | User stack ] |
793 | // |
794 | // Situation C [ User stack ( no room for guard page) ] |
795 | // |
796 | // Situation D (W9x) : Guard page or not, w9x has a 64k reserved region below |
797 | // the stack, we don't need any checks at all |
798 | // |
799 | // We really want to be in situation A all the time, so we add one more page |
800 | // to our requirements (we require guard page + hard guard) |
801 | |
802 | SYSTEM_INFO sysInfo; |
803 | ::GetSystemInfo(&sysInfo); |
804 | |
805 | // OS rounds up sizes the following way to decide if it marks a guard page |
806 | sizeReservedStack = ALIGN(sizeReservedStack, ((size_t)sysInfo.dwAllocationGranularity)); // Allocation granularity |
807 | sizeCommitedStack = ALIGN(sizeCommitedStack, ((size_t)sysInfo.dwPageSize)); // Page Size |
808 | |
809 | // OS wont create guard page, we can't execute managed code safely. |
810 | // We also have to make sure we have a 'hard' guard, thus we add another |
811 | // page to the memory we would need comitted. |
812 | // That is, the following code will check if sizeReservedStack is at least 2 pages |
813 | // more than sizeCommitedStack. |
814 | return (sizeReservedStack > sizeCommitedStack + ((size_t)sysInfo.dwPageSize)); |
815 | } // ThreadWillCreateGuardPage |
816 | |
817 | //The following characters have special sorting weights when combined with other |
818 | //characters, which means we can't use our fast sorting algorithm on them. |
819 | //Most of these are pretty rare control characters, but apostrophe and hyphen |
820 | //are fairly common and force us down the slower path. This is because we want |
821 | //"word sorting", which means that "coop" and "co-op" sort together, instead of |
822 | //separately as they would if we were doing a string sort. |
823 | // 0x0001 6 3 2 2 0 ;Start Of Heading |
824 | // 0x0002 6 4 2 2 0 ;Start Of Text |
825 | // 0x0003 6 5 2 2 0 ;End Of Text |
826 | // 0x0004 6 6 2 2 0 ;End Of Transmission |
827 | // 0x0005 6 7 2 2 0 ;Enquiry |
828 | // 0x0006 6 8 2 2 0 ;Acknowledge |
829 | // 0x0007 6 9 2 2 0 ;Bell |
830 | // 0x0008 6 10 2 2 0 ;Backspace |
831 | |
832 | // 0x000e 6 11 2 2 0 ;Shift Out |
833 | // 0x000f 6 12 2 2 0 ;Shift In |
834 | // 0x0010 6 13 2 2 0 ;Data Link Escape |
835 | // 0x0011 6 14 2 2 0 ;Device Control One |
836 | // 0x0012 6 15 2 2 0 ;Device Control Two |
837 | // 0x0013 6 16 2 2 0 ;Device Control Three |
838 | // 0x0014 6 17 2 2 0 ;Device Control Four |
839 | // 0x0015 6 18 2 2 0 ;Negative Acknowledge |
840 | // 0x0016 6 19 2 2 0 ;Synchronous Idle |
841 | // 0x0017 6 20 2 2 0 ;End Of Transmission Block |
842 | // 0x0018 6 21 2 2 0 ;Cancel |
843 | // 0x0019 6 22 2 2 0 ;End Of Medium |
844 | // 0x001a 6 23 2 2 0 ;Substitute |
845 | // 0x001b 6 24 2 2 0 ;Escape |
846 | // 0x001c 6 25 2 2 0 ;File Separator |
847 | // 0x001d 6 26 2 2 0 ;Group Separator |
848 | // 0x001e 6 27 2 2 0 ;Record Separator |
849 | // 0x001f 6 28 2 2 0 ;Unit Separator |
850 | |
851 | // 0x0027 6 128 2 2 0 ;Apostrophe-Quote |
852 | // 0x002d 6 130 2 2 0 ;Hyphen-Minus |
853 | |
854 | // 0x007f 6 29 2 2 0 ;Delete |
855 | |
856 | const BYTE |
857 | HighCharHelper::HighCharTable[]= { |
858 | TRUE, /* 0x0, 0x0 */ |
859 | TRUE, /* 0x1, .*/ |
860 | TRUE, /* 0x2, .*/ |
861 | TRUE, /* 0x3, .*/ |
862 | TRUE, /* 0x4, .*/ |
863 | TRUE, /* 0x5, .*/ |
864 | TRUE, /* 0x6, .*/ |
865 | TRUE, /* 0x7, .*/ |
866 | TRUE, /* 0x8, .*/ |
867 | FALSE, /* 0x9, */ |
868 | #ifdef PLATFORM_UNIX |
869 | TRUE, /* 0xA, */ |
870 | #else |
871 | FALSE, /* 0xA, */ |
872 | #endif // PLATFORM_UNIX |
873 | FALSE, /* 0xB, .*/ |
874 | FALSE, /* 0xC, .*/ |
875 | #ifdef PLATFORM_UNIX |
876 | TRUE, /* 0xD, */ |
877 | #else |
878 | FALSE, /* 0xD, */ |
879 | #endif // PLATFORM_UNIX |
880 | TRUE, /* 0xE, .*/ |
881 | TRUE, /* 0xF, .*/ |
882 | TRUE, /* 0x10, .*/ |
883 | TRUE, /* 0x11, .*/ |
884 | TRUE, /* 0x12, .*/ |
885 | TRUE, /* 0x13, .*/ |
886 | TRUE, /* 0x14, .*/ |
887 | TRUE, /* 0x15, .*/ |
888 | TRUE, /* 0x16, .*/ |
889 | TRUE, /* 0x17, .*/ |
890 | TRUE, /* 0x18, .*/ |
891 | TRUE, /* 0x19, .*/ |
892 | TRUE, /* 0x1A, */ |
893 | TRUE, /* 0x1B, .*/ |
894 | TRUE, /* 0x1C, .*/ |
895 | TRUE, /* 0x1D, .*/ |
896 | TRUE, /* 0x1E, .*/ |
897 | TRUE, /* 0x1F, .*/ |
898 | FALSE, /*0x20, */ |
899 | FALSE, /*0x21, !*/ |
900 | FALSE, /*0x22, "*/ |
901 | FALSE, /*0x23, #*/ |
902 | FALSE, /*0x24, $*/ |
903 | FALSE, /*0x25, %*/ |
904 | FALSE, /*0x26, &*/ |
905 | TRUE, /*0x27, '*/ |
906 | FALSE, /*0x28, (*/ |
907 | FALSE, /*0x29, )*/ |
908 | FALSE, /*0x2A **/ |
909 | FALSE, /*0x2B, +*/ |
910 | FALSE, /*0x2C, ,*/ |
911 | TRUE, /*0x2D, -*/ |
912 | FALSE, /*0x2E, .*/ |
913 | FALSE, /*0x2F, /*/ |
914 | FALSE, /*0x30, 0*/ |
915 | FALSE, /*0x31, 1*/ |
916 | FALSE, /*0x32, 2*/ |
917 | FALSE, /*0x33, 3*/ |
918 | FALSE, /*0x34, 4*/ |
919 | FALSE, /*0x35, 5*/ |
920 | FALSE, /*0x36, 6*/ |
921 | FALSE, /*0x37, 7*/ |
922 | FALSE, /*0x38, 8*/ |
923 | FALSE, /*0x39, 9*/ |
924 | FALSE, /*0x3A, :*/ |
925 | FALSE, /*0x3B, ;*/ |
926 | FALSE, /*0x3C, <*/ |
927 | FALSE, /*0x3D, =*/ |
928 | FALSE, /*0x3E, >*/ |
929 | FALSE, /*0x3F, ?*/ |
930 | FALSE, /*0x40, @*/ |
931 | FALSE, /*0x41, A*/ |
932 | FALSE, /*0x42, B*/ |
933 | FALSE, /*0x43, C*/ |
934 | FALSE, /*0x44, D*/ |
935 | FALSE, /*0x45, E*/ |
936 | FALSE, /*0x46, F*/ |
937 | FALSE, /*0x47, G*/ |
938 | FALSE, /*0x48, H*/ |
939 | FALSE, /*0x49, I*/ |
940 | FALSE, /*0x4A, J*/ |
941 | FALSE, /*0x4B, K*/ |
942 | FALSE, /*0x4C, L*/ |
943 | FALSE, /*0x4D, M*/ |
944 | FALSE, /*0x4E, N*/ |
945 | FALSE, /*0x4F, O*/ |
946 | FALSE, /*0x50, P*/ |
947 | FALSE, /*0x51, Q*/ |
948 | FALSE, /*0x52, R*/ |
949 | FALSE, /*0x53, S*/ |
950 | FALSE, /*0x54, T*/ |
951 | FALSE, /*0x55, U*/ |
952 | FALSE, /*0x56, V*/ |
953 | FALSE, /*0x57, W*/ |
954 | FALSE, /*0x58, X*/ |
955 | FALSE, /*0x59, Y*/ |
956 | FALSE, /*0x5A, Z*/ |
957 | FALSE, /*0x5B, [*/ |
958 | FALSE, /*0x5C, \*/ |
959 | FALSE, /*0x5D, ]*/ |
960 | FALSE, /*0x5E, ^*/ |
961 | FALSE, /*0x5F, _*/ |
962 | FALSE, /*0x60, `*/ |
963 | FALSE, /*0x61, a*/ |
964 | FALSE, /*0x62, b*/ |
965 | FALSE, /*0x63, c*/ |
966 | FALSE, /*0x64, d*/ |
967 | FALSE, /*0x65, e*/ |
968 | FALSE, /*0x66, f*/ |
969 | FALSE, /*0x67, g*/ |
970 | FALSE, /*0x68, h*/ |
971 | FALSE, /*0x69, i*/ |
972 | FALSE, /*0x6A, j*/ |
973 | FALSE, /*0x6B, k*/ |
974 | FALSE, /*0x6C, l*/ |
975 | FALSE, /*0x6D, m*/ |
976 | FALSE, /*0x6E, n*/ |
977 | FALSE, /*0x6F, o*/ |
978 | FALSE, /*0x70, p*/ |
979 | FALSE, /*0x71, q*/ |
980 | FALSE, /*0x72, r*/ |
981 | FALSE, /*0x73, s*/ |
982 | FALSE, /*0x74, t*/ |
983 | FALSE, /*0x75, u*/ |
984 | FALSE, /*0x76, v*/ |
985 | FALSE, /*0x77, w*/ |
986 | FALSE, /*0x78, x*/ |
987 | FALSE, /*0x79, y*/ |
988 | FALSE, /*0x7A, z*/ |
989 | FALSE, /*0x7B, {*/ |
990 | FALSE, /*0x7C, |*/ |
991 | FALSE, /*0x7D, }*/ |
992 | FALSE, /*0x7E, ~*/ |
993 | TRUE, /*0x7F, */ |
994 | }; // HighCharHelper::HighCharTable |
995 | |