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
20RunningOnStatusEnum 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//*****************************************************************************
29void 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
82CHECK_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.
98BOOL 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//------------------------------------------------------------------------------
139BOOL 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//----------------------------------------------------------------------------
199HRESULT 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//----------------------------------------------------------------------------
232BOOL 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//*****************************************************************************
275void 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.
346HRESULT 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//*****************************************************************************
481HRESULT 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//*****************************************************************************
514int
515GuidToLPWSTR(
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//*****************************************************************************
582HRESULT 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//*****************************************************************************
626BOOL
627LPWSTRToGuid(
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.
701void _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/**************************************************************************/
720void 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//
747void 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
775BOOL 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
856const BYTE
857HighCharHelper::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