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.hpp
6//
7
8//
9// Miscellaneous useful functions
10//
11
12#ifndef _H_UTIL
13#define _H_UTIL
14
15#define MAX_UINT32_HEX_CHAR_LEN 8 // max number of chars representing an unsigned int32, not including terminating null char.
16#define MAX_INT32_DECIMAL_CHAR_LEN 11 // max number of chars representing an int32, including sign, not including terminating null char.
17
18#include "utilcode.h"
19#include "metadata.h"
20#include "holderinst.h"
21#include "clrdata.h"
22#include "xclrdata.h"
23#include "posterror.h"
24#include "clr_std/type_traits"
25
26
27// Prevent the use of UtilMessageBox and WszMessageBox from inside the EE.
28#undef UtilMessageBoxCatastrophic
29#undef UtilMessageBoxCatastrophicNonLocalized
30#undef UtilMessageBoxCatastrophic
31#undef UtilMessageBoxCatastrophicNonLocalizedVA
32#undef UtilMessageBox
33#undef UtilMessageBoxNonLocalized
34#undef UtilMessageBoxVA
35#undef UtilMessageBoxNonLocalizedVA
36#undef WszMessageBox
37#define UtilMessageBoxCatastrophic __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
38#define UtilMessageBoxCatastrophicNonLocalized __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
39#define UtilMessageBoxCatastrophicVA __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
40#define UtilMessageBoxCatastrophicNonLocalizedVA __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
41#define UtilMessageBox __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
42#define UtilMessageBoxNonLocalized __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
43#define UtilMessageBoxVA __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
44#define UtilMessageBoxNonLocalizedVA __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
45#define WszMessageBox __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE")
46
47// Hot cache lines need to be aligned to cache line size to improve performance
48#if defined(ARM64)
49#define MAX_CACHE_LINE_SIZE 128
50#else
51#define MAX_CACHE_LINE_SIZE 64
52#endif
53
54//========================================================================
55// More convenient names for integer types of a guaranteed size.
56//========================================================================
57
58typedef __int8 I1;
59typedef ArrayDPTR(I1) PTR_I1;
60typedef unsigned __int8 U1;
61typedef __int16 I2;
62typedef unsigned __int16 U2;
63typedef __int32 I4;
64typedef unsigned __int32 U4;
65typedef __int64 I8;
66typedef unsigned __int64 U8;
67typedef float R4;
68typedef double R8;
69
70//
71// Forward the FastInterlock methods to the matching Win32 APIs. They are implemented
72// using compiler intrinsics so they are as fast as they can possibly be.
73//
74
75//
76// these don't have corresponding compiler intrinsics
77//
78
79#ifdef FEATURE_SINGLE_THREADED
80#define FastInterlockIncrement(a) (++(*a))
81#define FastInterlockDecrement(a) (--(*a))
82#define FastInterlockOr(a, b) (*a |= (DWORD)b)
83#define FastInterlockAnd(a, b) (*a &= (DWORD)b)
84#define FastInterlockIncrementLong(a) (++(*a))
85#define FastInterlockDecrementLong(a) (--(*a))
86#define FastInterlockOrLong(a, b) (*a |= (UINT64)b)
87#define FastInterlockAndLong(a, b) (*a &= (UINT64)b)
88#define FastInterlockCompareExchange InterlockedCompareExchange
89#define FastInterlockCompareExchangePointer InterlockedCompareExchangeT
90
91#else
92
93//
94// these DO have corresponding compiler intrinsics
95//
96#define FastInterlockIncrement InterlockedIncrement
97#define FastInterlockDecrement InterlockedDecrement
98#define FastInterlockExchange InterlockedExchange
99#define FastInterlockCompareExchange InterlockedCompareExchange
100#define FastInterlockExchangeAdd InterlockedExchangeAdd
101#define FastInterlockExchangeLong InterlockedExchange64
102#define FastInterlockCompareExchangeLong InterlockedCompareExchange64
103#define FastInterlockExchangeAddLong InterlockedExchangeAdd64
104
105//
106// Forward FastInterlock[Compare]ExchangePointer to the
107// Utilcode Interlocked[Compare]ExchangeT.
108//
109#define FastInterlockExchangePointer InterlockedExchangeT
110#define FastInterlockCompareExchangePointer InterlockedCompareExchangeT
111
112FORCEINLINE void FastInterlockOr(DWORD RAW_KEYWORD(volatile) *p, const int msk)
113{
114 LIMITED_METHOD_CONTRACT;
115
116 InterlockedOr((LONG *)p, msk);
117}
118
119FORCEINLINE void FastInterlockAnd(DWORD RAW_KEYWORD(volatile) *p, const int msk)
120{
121 LIMITED_METHOD_CONTRACT;
122
123 InterlockedAnd((LONG *)p, msk);
124}
125
126#endif
127
128#ifndef FEATURE_PAL
129// Copied from malloc.h: don't want to bring in the whole header file.
130void * __cdecl _alloca(size_t);
131#endif // !FEATURE_PAL
132
133#ifdef _PREFAST_
134// Suppress prefast warning #6255: alloca indicates failure by raising a stack overflow exception
135#pragma warning(disable:6255)
136#endif // _PREFAST_
137
138// Function to parse apart a command line and return the
139// arguments just like argv and argc
140LPWSTR* CommandLineToArgvW(__in LPWSTR lpCmdLine, DWORD *pNumArgs);
141#define ISWWHITE(x) ((x)==W(' ') || (x)==W('\t') || (x)==W('\n') || (x)==W('\r') )
142
143BOOL inline FitsInI1(__int64 val)
144{
145 LIMITED_METHOD_DAC_CONTRACT;
146 return val == (__int64)(__int8)val;
147}
148
149BOOL inline FitsInI2(__int64 val)
150{
151 LIMITED_METHOD_CONTRACT;
152 return val == (__int64)(__int16)val;
153}
154
155BOOL inline FitsInI4(__int64 val)
156{
157 LIMITED_METHOD_DAC_CONTRACT;
158 return val == (__int64)(__int32)val;
159}
160
161BOOL inline FitsInU1(unsigned __int64 val)
162{
163 LIMITED_METHOD_CONTRACT;
164 return val == (unsigned __int64)(unsigned __int8)val;
165}
166
167BOOL inline FitsInU2(unsigned __int64 val)
168{
169 LIMITED_METHOD_CONTRACT;
170 return val == (unsigned __int64)(unsigned __int16)val;
171}
172
173BOOL inline FitsInU4(unsigned __int64 val)
174{
175 LIMITED_METHOD_DAC_CONTRACT;
176 return val == (unsigned __int64)(unsigned __int32)val;
177}
178
179// returns FALSE if overflows 15 bits: otherwise, (*pa) is incremented by b
180BOOL inline SafeAddUINT15(UINT16 *pa, ULONG b)
181{
182 LIMITED_METHOD_CONTRACT;
183
184 UINT16 a = *pa;
185 // first check if overflows 16 bits
186 if ( ((UINT16)b) != b )
187 {
188 return FALSE;
189 }
190 // now make sure that doesn't overflow 15 bits
191 if (((ULONG)a + b) > 0x00007FFF)
192 {
193 return FALSE;
194 }
195 (*pa) += (UINT16)b;
196 return TRUE;
197}
198
199
200// returns FALSE if overflows 16 bits: otherwise, (*pa) is incremented by b
201BOOL inline SafeAddUINT16(UINT16 *pa, ULONG b)
202{
203 UINT16 a = *pa;
204 if ( ((UINT16)b) != b )
205 {
206 return FALSE;
207 }
208 // now make sure that doesn't overflow 16 bits
209 if (((ULONG)a + b) > 0x0000FFFF)
210 {
211 return FALSE;
212 }
213 (*pa) += (UINT16)b;
214 return TRUE;
215}
216
217
218// returns FALSE if overflow: otherwise, (*pa) is incremented by b
219BOOL inline SafeAddUINT32(UINT32 *pa, UINT32 b)
220{
221 LIMITED_METHOD_CONTRACT;
222
223 UINT32 a = *pa;
224 if ( ((UINT32)(a + b)) < a)
225 {
226 return FALSE;
227 }
228 (*pa) += b;
229 return TRUE;
230}
231
232// returns FALSE if overflow: otherwise, (*pa) is incremented by b
233BOOL inline SafeAddULONG(ULONG *pa, ULONG b)
234{
235 LIMITED_METHOD_CONTRACT;
236
237 ULONG a = *pa;
238 if ( ((ULONG)(a + b)) < a)
239 {
240 return FALSE;
241 }
242 (*pa) += b;
243 return TRUE;
244}
245
246// returns FALSE if overflow: otherwise, (*pa) is multiplied by b
247BOOL inline SafeMulSIZE_T(SIZE_T *pa, SIZE_T b)
248{
249 LIMITED_METHOD_CONTRACT;
250
251#ifdef _DEBUG_IMPL
252 {
253 //Make sure SIZE_T is unsigned
254 SIZE_T m = ((SIZE_T)(-1));
255 SIZE_T z = 0;
256 _ASSERTE(m > z);
257 }
258#endif
259
260
261 SIZE_T a = *pa;
262 const SIZE_T m = ((SIZE_T)(-1));
263 if ( (m / b) < a )
264 {
265 return FALSE;
266 }
267 (*pa) *= b;
268 return TRUE;
269}
270
271
272
273//************************************************************************
274// CQuickHeap
275//
276// A fast non-multithread-safe heap for short term use.
277// Destroying the heap frees all blocks allocated from the heap.
278// Blocks cannot be freed individually.
279//
280// The heap uses COM+ exceptions to report errors.
281//
282// The heap does not use any internal synchronization so it is not
283// multithreadsafe.
284//************************************************************************
285class CQuickHeap
286{
287 public:
288 CQuickHeap();
289 ~CQuickHeap();
290
291 //---------------------------------------------------------------
292 // Allocates a block of "sz" bytes. If there's not enough
293 // memory, throws an OutOfMemoryError.
294 //---------------------------------------------------------------
295 LPVOID Alloc(UINT sz);
296
297
298 private:
299 enum {
300#ifdef _DEBUG
301 kBlockSize = 24
302#else
303 kBlockSize = 1024
304#endif
305 };
306
307 // The QuickHeap allocates QuickBlock's as needed and chains
308 // them in a single-linked list. Most QuickBlocks have a size
309 // of kBlockSize bytes (not counting m_next), and individual
310 // allocation requests are suballocated from them.
311 // Allocation requests of greater than kBlockSize are satisfied
312 // by allocating a special big QuickBlock of the right size.
313 struct QuickBlock
314 {
315 QuickBlock *m_next;
316 BYTE m_bytes[1];
317 };
318
319
320 // Linked list of QuickBlock's.
321 QuickBlock *m_pFirstQuickBlock;
322
323 // Offset to next available byte in m_pFirstQuickBlock.
324 LPBYTE m_pNextFree;
325
326 // Linked list of big QuickBlock's
327 QuickBlock *m_pFirstBigQuickBlock;
328
329};
330
331//======================================================================
332// String Helpers
333//
334//
335//
336ULONG StringHashValueW(__in LPWSTR wzString);
337ULONG StringHashValueA(LPCSTR szString);
338
339void PrintToStdOutA(const char *pszString);
340void PrintToStdOutW(const WCHAR *pwzString);
341void PrintToStdErrA(const char *pszString);
342void PrintToStdErrW(const WCHAR *pwzString);
343void NPrintToStdOutA(const char *pszString, size_t nbytes);
344void NPrintToStdOutW(const WCHAR *pwzString, size_t nchars);
345void NPrintToStdErrA(const char *pszString, size_t nbytes);
346void NPrintToStdErrW(const WCHAR *pwzString, size_t nchars);
347
348
349//=====================================================================
350// Function for formatted text output to the debugger
351//
352//
353void __cdecl VMDebugOutputA(__in LPSTR format, ...);
354void __cdecl VMDebugOutputW(__in LPWSTR format, ...);
355
356//=====================================================================
357// VM-safe wrapper for PostError.
358//
359HRESULT VMPostError( // Returned error.
360 HRESULT hrRpt, // Reported error.
361 ...); // Error arguments.
362
363//=====================================================================
364// Displays the messaage box or logs the message, corresponding to the last COM+ error occurred
365void VMDumpCOMErrors(HRESULT hrErr);
366
367#include "nativevaraccessors.h"
368
369//======================================================================
370// Stack friendly registry helpers
371//
372LONG UtilRegEnumKey(HKEY hKey, // handle to key to query
373 DWORD dwIndex, // index of subkey to query
374 CQuickWSTR* lpName);// buffer for subkey name
375
376LONG UtilRegQueryStringValueEx(HKEY hKey, // handle to key to query
377 LPCWSTR lpValueName, // address of name of value to query
378 LPDWORD lpReserved, // reserved
379 LPDWORD lpType, // address of buffer for value type
380 CQuickWSTR* lpData);// data buffer
381
382//======================================================================
383// Event logging
384
385BOOL ReportEventCLR (
386 IN WORD wType, // Event type - warning, error, success, etc
387 IN WORD wCategory, // Event category
388 IN DWORD dwEventID, // Event identifier (defined in shimr\msg.mc)
389 IN PSID lpUserSid, // user's security identifier
390 IN SString * message // message to log
391 );
392
393// --------------------------------------------------------------------------------
394// GCX macros
395//
396// These are the normal way to change or assert the GC mode of a thread. They handle
397// the required stack discipline in mode switches with an autodestructor which
398// automatically triggers on leaving the current scope.
399//
400// Usage:
401// GCX_COOP(); Switch to cooperative mode, assume thread is setup
402// GCX_PREEMP(); Switch to preemptive mode, NOP if no thread setup
403// GCX_COOP_THREAD_EXISTS(Thread*); Fast switch to cooperative mode, must pass non-null Thread
404// GCX_PREEMP_THREAD_EXISTS(Thread*); Fast switch to preemptive mode, must pass non-null Thread
405//
406// (There is an intentional asymmetry between GCX_COOP and GCX_PREEMP. GCX_COOP
407// asserts if you call it without having a Thread setup. GCX_PREEMP becomes a NOP.
408// This is because all unmanaged threads are effectively preemp.)
409//
410// (There is actually one more case here - an "EE worker thread" such as the debugger
411// thread or GC thread, which we don't want to call SetupThread() on, but which is
412// effectively in cooperative mode due to explicit cooperation with the collector.
413// This case is not handled by these macros; the current working assumption is that
414// such threads never use them. But at some point we may have to consider
415// this case if there is utility code which is called from those threads.)
416//
417// GCX_MAYBE_*(BOOL); Same as above, but only do the switch if BOOL is TRUE.
418//
419// GCX_ASSERT_*(); Same as above, but assert mode rather than switch to mode.
420// Note that assert is applied during backout as well.
421// No overhead in a free build.
422//
423// GCX_FORBID(); Add "ForbidGC" semantics to a cooperative mode situation.
424// Asserts that the thread will not trigger a GC or
425// reach a GC-safe point, or call anything that might
426// do one of these things.
427//
428// GCX_NOTRIGGER(); "ForbidGC" without the automatic assertion for coop mode.
429//
430// --------------------------------------------------------------------------------
431
432template<BOOL COOPERATIVE>
433class AutoCleanupGCAssert;
434
435template<BOOL COOPERATIVE>
436class GCAssert;
437
438
439typedef AutoCleanupGCAssert<TRUE> AutoCleanupGCAssertCoop;
440typedef AutoCleanupGCAssert<FALSE> AutoCleanupGCAssertPreemp;
441
442typedef GCAssert<TRUE> GCAssertCoop;
443typedef GCAssert<FALSE> GCAssertPreemp;
444
445#if !defined(CROSSGEN_COMPILE) && !defined(DACCESS_COMPILE)
446
447#ifdef ENABLE_CONTRACTS_IMPL
448#define GCX_COOP() GCCoop __gcHolder("GCX_COOP", __FUNCTION__, __FILE__, __LINE__)
449#define GCX_COOP_NO_DTOR() GCCoopNoDtor __gcHolder; __gcHolder.Enter(TRUE, "GCX_COOP_NO_DTOR", __FUNCTION__, __FILE__, __LINE__)
450#define GCX_COOP_NO_DTOR_END() __gcHolder.Leave();
451#else
452#define GCX_COOP() GCCoop __gcHolder
453#define GCX_COOP_NO_DTOR() GCCoopNoDtor __gcHolder; __gcHolder.Enter(TRUE)
454#define GCX_COOP_NO_DTOR_END() __gcHolder.Leave();
455#endif
456
457#ifdef ENABLE_CONTRACTS_IMPL
458#define GCX_PREEMP() GCPreemp __gcHolder("GCX_PREEMP", __FUNCTION__, __FILE__, __LINE__)
459#define GCX_PREEMP_NO_DTOR() GCPreempNoDtor __gcHolder; __gcHolder.Enter(TRUE, "GCX_PREEMP_NO_DTOR", __FUNCTION__, __FILE__, __LINE__)
460#define GCX_PREEMP_NO_DTOR_HAVE_THREAD(curThreadNullOk) GCPreempNoDtor __gcHolder; __gcHolder.Enter(curThreadNullOk, TRUE, "GCX_PREEMP_NO_DTOR_HAVE_THREAD", __FUNCTION__, __FILE__, __LINE__)
461#define GCX_PREEMP_NO_DTOR_END() __gcHolder.Leave();
462#else
463#define GCX_PREEMP() GCPreemp __gcHolder
464#define GCX_PREEMP_NO_DTOR_HAVE_THREAD(curThreadNullOk) GCPreempNoDtor __gcHolder; __gcHolder.Enter(curThreadNullOk, TRUE)
465#define GCX_PREEMP_NO_DTOR() GCPreempNoDtor __gcHolder; __gcHolder.Enter(TRUE)
466#define GCX_PREEMP_NO_DTOR_END() __gcHolder.Leave()
467#endif
468
469#ifdef ENABLE_CONTRACTS_IMPL
470#define GCX_COOP_THREAD_EXISTS(curThread) GCCoopThreadExists __gcHolder((curThread), "GCX_COOP_THREAD_EXISTS", __FUNCTION__, __FILE__, __LINE__)
471#else
472#define GCX_COOP_THREAD_EXISTS(curThread) GCCoopThreadExists __gcHolder((curThread))
473#endif
474
475#ifdef ENABLE_CONTRACTS_IMPL
476#define GCX_PREEMP_THREAD_EXISTS(curThread) GCPreempThreadExists __gcHolder((curThread), "GCX_PREEMP_THREAD_EXISTS", __FUNCTION__, __FILE__, __LINE__)
477#else
478#define GCX_PREEMP_THREAD_EXISTS(curThread) GCPreempThreadExists __gcHolder((curThread))
479#endif
480
481#ifdef ENABLE_CONTRACTS_IMPL
482#define GCX_MAYBE_COOP(_cond) GCCoop __gcHolder(_cond, "GCX_MAYBE_COOP", __FUNCTION__, __FILE__, __LINE__)
483#define GCX_MAYBE_COOP_NO_DTOR(_cond) GCCoopNoDtor __gcHolder; __gcHolder.Enter(_cond, "GCX_MAYBE_COOP_NO_DTOR", __FUNCTION__, __FILE__, __LINE__)
484#define GCX_MAYBE_COOP_NO_DTOR_END() __gcHolder.Leave();
485#else
486#define GCX_MAYBE_COOP(_cond) GCCoop __gcHolder(_cond)
487#define GCX_MAYBE_COOP_NO_DTOR(_cond) GCCoopNoDtor __gcHolder; __gcHolder.Enter(_cond)
488#define GCX_MAYBE_COOP_NO_DTOR_END() __gcHolder.Leave();
489#endif
490
491#ifdef ENABLE_CONTRACTS_IMPL
492#define GCX_MAYBE_PREEMP(_cond) GCPreemp __gcHolder(_cond, "GCX_MAYBE_PREEMP", __FUNCTION__, __FILE__, __LINE__)
493#define GCX_MAYBE_PREEMP_NO_DTOR(_cond) GCPreempNoDtor __gcHolder; __gcHolder.Enter(_cond, "GCX_MAYBE_PREEMP_NO_DTOR", __FUNCTION__, __FILE__, __LINE__)
494#define GCX_MAYBE_PREEMP_NO_DTOR_END() __gcHolder.Leave();
495#else
496#define GCX_MAYBE_PREEMP(_cond) GCPreemp __gcHolder(_cond)
497#define GCX_MAYBE_PREEMP_NO_DTOR(_cond) GCPreempNoDtor __gcHolder; __gcHolder.Enter(_cond)
498#define GCX_MAYBE_PREEMP_NO_DTOR_END() __gcHolder.Leave()
499#endif
500
501#ifdef ENABLE_CONTRACTS_IMPL
502#define GCX_MAYBE_COOP_THREAD_EXISTS(curThread, _cond) GCCoopThreadExists __gcHolder((curThread), (_cond), "GCX_MAYBE_COOP_THREAD_EXISTS", __FUNCTION__, __FILE__, __LINE__)
503#else
504#define GCX_MAYBE_COOP_THREAD_EXISTS(curThread, _cond) GCCoopThreadExists __gcHolder((curThread), (_cond))
505#endif
506
507#ifdef ENABLE_CONTRACTS_IMPL
508#define GCX_MAYBE_PREEMP_THREAD_EXISTS(curThread, _cond) GCPreempThreadExists __gcHolder((curThread), (_cond), "GCX_MAYBE_PREEMP_THREAD_EXISTS", __FUNCTION__, __FILE__, __LINE__)
509#else
510#define GCX_MAYBE_PREEMP_THREAD_EXISTS(curThread, _cond) GCPreempThreadExists __gcHolder((curThread), (_cond))
511#endif
512
513// This has a potential race with the GC thread. It is currently
514// used for a few cases where (a) we potentially haven't started up the EE yet, or
515// (b) we are on a "special thread".
516#ifdef ENABLE_CONTRACTS_IMPL
517#define GCX_COOP_NO_THREAD_BROKEN() GCCoopHackNoThread __gcHolder("GCX_COOP_NO_THREAD_BROKEN", __FUNCTION__, __FILE__, __LINE__)
518#else
519#define GCX_COOP_NO_THREAD_BROKEN() GCCoopHackNoThread __gcHolder
520#endif
521
522
523#ifdef ENABLE_CONTRACTS_IMPL
524#define GCX_MAYBE_COOP_NO_THREAD_BROKEN(_cond) GCCoopHackNoThread __gcHolder(_cond, "GCX_MAYBE_COOP_NO_THREAD_BROKEN", __FUNCTION__, __FILE__, __LINE__)
525#else
526#define GCX_MAYBE_COOP_NO_THREAD_BROKEN(_cond) GCCoopHackNoThread __gcHolder(_cond)
527#endif
528
529#else // !defined(CROSSGEN_COMPILE) && !defined(DACCESS_COMPILE)
530
531#define GCX_COOP()
532#define GCX_COOP_NO_DTOR()
533#define GCX_COOP_NO_DTOR_END()
534
535#define GCX_PREEMP()
536#define GCX_PREEMP_NO_DTOR()
537#define GCX_PREEMP_NO_DTOR_HAVE_THREAD(curThreadNullOk)
538#define GCX_PREEMP_NO_DTOR_END()
539
540#define GCX_MAYBE_PREEMP(_cond)
541
542#define GCX_COOP_NO_THREAD_BROKEN()
543#define GCX_MAYBE_COOP_NO_THREAD_BROKEN(_cond)
544
545#define GCX_PREEMP_THREAD_EXISTS(curThread)
546#define GCX_COOP_THREAD_EXISTS(curThread)
547
548#define GCX_POP()
549
550#endif // !defined(CROSSGEN_COMPILE) && !defined(DACCESS_COMPILE)
551
552#if defined(_DEBUG_IMPL) && !defined(CROSSGEN_COMPILE)
553
554#define GCX_ASSERT_PREEMP() ::AutoCleanupGCAssertPreemp __gcHolder
555#define GCX_ASSERT_COOP() ::AutoCleanupGCAssertCoop __gcHolder
556
557#define BEGIN_GCX_ASSERT_COOP \
558 { \
559 GCAssertCoop __gcHolder; \
560 __gcHolder.BeginGCAssert()
561
562#define END_GCX_ASSERT_COOP \
563 __gcHolder.EndGCAssert(); \
564 }
565
566#define BEGIN_GCX_ASSERT_PREEMP \
567 { \
568 GCAssertPreemp __gcHolder; \
569 __gcHolder.BeginGCAssert()
570
571#define END_GCX_ASSERT_PREEMP \
572 __gcHolder.EndGCAssert(); \
573 }
574
575
576#else
577
578#define GCX_ASSERT_PREEMP()
579#define GCX_ASSERT_COOP()
580
581#define BEGIN_GCX_ASSERT_COOP \
582 {
583#define END_GCX_ASSERT_COOP \
584 }
585#define BEGIN_GCX_ASSERT_PREEMP \
586 {
587#define END_GCX_ASSERT_PREEMP \
588 }
589
590#endif
591
592#ifdef ENABLE_CONTRACTS_IMPL
593
594#define GCX_FORBID() ::GCForbid __gcForbidHolder(__FUNCTION__, __FILE__, __LINE__)
595#define GCX_NOTRIGGER() ::GCNoTrigger __gcNoTriggerHolder(__FUNCTION__, __FILE__, __LINE__)
596
597#define GCX_MAYBE_FORBID(fConditional) ::GCForbid __gcForbidHolder(fConditional, __FUNCTION__, __FILE__, __LINE__)
598#define GCX_MAYBE_NOTRIGGER(fConditional) ::GCNoTrigger __gcNoTriggerHolder(fConditional, __FUNCTION__, __FILE__, __LINE__)
599
600#else
601
602
603#define GCX_FORBID()
604#define GCX_NOTRIGGER()
605
606#define GCX_MAYBE_FORBID(fConditional)
607#define GCX_MAYBE_NOTRIGGER(fConditional)
608
609#endif
610
611typedef BOOL (*FnLockOwner)(LPVOID);
612struct LockOwner
613{
614 LPVOID lock;
615 FnLockOwner lockOwnerFunc;
616};
617
618// this is the standard lockowner for things that require a lock owner but which really don't
619// need any validation due to their simple/safe semantics
620// the classic example of this is a hash table that is initialized and then never grows
621extern LockOwner g_lockTrustMeIAmThreadSafe;
622
623// The OS ThreadId is not a stable ID for a thread we a host uses fiber instead of Thread.
624// For each managed Thread, we have a stable and unique id in Thread object. For other threads,
625// e.g. Server GC or Concurrent GC thread, debugger helper thread, we do not have a Thread object,
626// and we use OS ThreadId to identify them since they are not managed by a host.
627class EEThreadId
628{
629private:
630 void *m_FiberPtrId;
631public:
632#ifdef _DEBUG
633 EEThreadId()
634 : m_FiberPtrId(NULL)
635 {
636 LIMITED_METHOD_CONTRACT;
637 }
638#endif
639
640 void SetToCurrentThread()
641 {
642 WRAPPER_NO_CONTRACT;
643
644 m_FiberPtrId = ClrTeb::GetFiberPtrId();
645 }
646
647 bool IsCurrentThread() const
648 {
649 WRAPPER_NO_CONTRACT;
650
651 return (m_FiberPtrId == ClrTeb::GetFiberPtrId());
652 }
653
654
655#ifdef _DEBUG
656 bool IsUnknown() const
657 {
658 LIMITED_METHOD_CONTRACT;
659 return m_FiberPtrId == NULL;
660 }
661#endif
662 void Clear()
663 {
664 LIMITED_METHOD_CONTRACT;
665 m_FiberPtrId = NULL;
666 }
667};
668
669#define CLRHOSTED 0x80000000
670
671GVAL_DECL(DWORD, g_fHostConfig);
672
673
674inline BOOL CLRHosted()
675{
676 LIMITED_METHOD_CONTRACT;
677
678 return g_fHostConfig;
679}
680
681#ifndef FEATURE_PAL
682HMODULE CLRGetModuleHandle(LPCWSTR lpModuleFileName);
683
684// Equivalent to CLRGetModuleHandle(NULL) but doesn't have the INJECT_FAULT contract associated
685// with CLRGetModuleHandle.
686HMODULE CLRGetCurrentModuleHandle();
687
688HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
689#endif // !FEATURE_PAL
690
691HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName);
692
693BOOL CLRFreeLibrary(HMODULE hModule);
694VOID CLRFreeLibraryAndExitThread(HMODULE hModule, DWORD dwExitCode);
695
696LPVOID
697CLRMapViewOfFileEx(
698 IN HANDLE hFileMappingObject,
699 IN DWORD dwDesiredAccess,
700 IN DWORD dwFileOffsetHigh,
701 IN DWORD dwFileOffsetLow,
702 IN SIZE_T dwNumberOfBytesToMap,
703 IN LPVOID lpBaseAddress
704 );
705
706LPVOID
707CLRMapViewOfFile(
708 IN HANDLE hFileMappingObject,
709 IN DWORD dwDesiredAccess,
710 IN DWORD dwFileOffsetHigh,
711 IN DWORD dwFileOffsetLow,
712 IN SIZE_T dwNumberOfBytesToMap
713 );
714
715
716BOOL
717CLRUnmapViewOfFile(
718 IN LPVOID lpBaseAddress
719 );
720
721BOOL CompareFiles(HANDLE hFile1,HANDLE hFile2);
722
723
724#ifndef DACCESS_COMPILE
725FORCEINLINE void VoidCLRUnmapViewOfFile(void *ptr) { CLRUnmapViewOfFile(ptr); }
726typedef Wrapper<void *, DoNothing, VoidCLRUnmapViewOfFile> CLRMapViewHolder;
727#else
728typedef Wrapper<void *, DoNothing, DoNothing> CLRMapViewHolder;
729#endif
730
731#ifdef FEATURE_PAL
732#ifndef DACCESS_COMPILE
733FORCEINLINE void VoidPALUnloadPEFile(void *ptr) { PAL_LOADUnloadPEFile(ptr); }
734typedef Wrapper<void *, DoNothing, VoidPALUnloadPEFile> PALPEFileHolder;
735#else
736typedef Wrapper<void *, DoNothing, DoNothing> PALPEFileHolder;
737#endif
738#endif // FEATURE_PAL
739
740void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX);
741
742void ProcessEventForHost(EClrEvent event, void *data);
743void ProcessSOEventForHost(EXCEPTION_POINTERS *pExceptionInfo, BOOL fInSoTolerant);
744BOOL IsHostRegisteredForEvent(EClrEvent event);
745
746#define SetupThreadForComCall(OOMRetVal) \
747 MAKE_CURRENT_THREAD_AVAILABLE_EX(GetThreadNULLOk()); \
748 if (CURRENT_THREAD == NULL) \
749 { \
750 CURRENT_THREAD = SetupThreadNoThrow(); \
751 if (CURRENT_THREAD == NULL) \
752 return OOMRetVal; \
753 } \
754
755
756#define InternalSetupForComCall(CannotEnterRetVal, OOMRetVal, SORetVal, CheckCanRunManagedCode) \
757SetupThreadForComCall(OOMRetVal); \
758if (CheckCanRunManagedCode && !CanRunManagedCode()) \
759 return CannotEnterRetVal; \
760SO_INTOLERANT_CODE_NOTHROW(CURRENT_THREAD, return SORetVal)
761
762#define SetupForComCallHRNoHostNotif() InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true)
763#define SetupForComCallHRNoHostNotifNoCheckCanRunManagedCode() InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, false)
764#define SetupForComCallDWORDNoHostNotif() InternalSetupForComCall(-1, -1, -1, true)
765
766#define SetupForComCallHR() \
767InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true)
768
769#define SetupForComCallHRNoCheckCanRunManagedCode() \
770InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, false)
771
772#ifdef FEATURE_CORRUPTING_EXCEPTIONS
773
774// Since Corrupting exceptions can escape COM interop boundaries,
775// these macros will be used to setup the initial SO-Intolerant transition.
776#define InternalSetupForComCallWithEscapingCorruptingExceptions(CannotEnterRetVal, OOMRetVal, SORetVal, CheckCanRunManagedCode) \
777if (CheckCanRunManagedCode && !CanRunManagedCode()) \
778 return CannotEnterRetVal; \
779SetupThreadForComCall(OOMRetVal); \
780BEGIN_SO_INTOLERANT_CODE_NOTHROW(CURRENT_THREAD, SORetVal) \
781
782#define BeginSetupForComCallHRWithEscapingCorruptingExceptions() \
783HRESULT __hr = S_OK; \
784InternalSetupForComCallWithEscapingCorruptingExceptions(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true) \
785 \
786if (SUCCEEDED(__hr)) \
787{ \
788
789#define EndSetupForComCallHRWithEscapingCorruptingExceptions() \
790} \
791END_SO_INTOLERANT_CODE; \
792 \
793if (FAILED(__hr)) \
794{ \
795 return __hr; \
796} \
797
798#endif // FEATURE_CORRUPTING_EXCEPTIONS
799
800#define SetupForComCallDWORD() \
801InternalSetupForComCall(-1, -1, -1, true)
802
803// Special version of SetupForComCallDWORD that doesn't call
804// CanRunManagedCode() to avoid firing LoaderLock MDA
805#define SetupForComCallDWORDNoCheckCanRunManagedCode() \
806InternalSetupForComCall(-1, -1, -1, false)
807
808#include "unsafe.h"
809
810inline void UnsafeTlsFreeForHolder(DWORD* addr)
811{
812 WRAPPER_NO_CONTRACT;
813
814 if (addr && *addr != TLS_OUT_OF_INDEXES) {
815 UnsafeTlsFree(*addr);
816 *addr = TLS_OUT_OF_INDEXES;
817 }
818}
819
820// A holder to make sure tls slot is released and memory for allocated one is set to TLS_OUT_OF_INDEXES
821typedef Holder<DWORD*, DoNothing<DWORD*>, UnsafeTlsFreeForHolder> TlsHolder;
822
823// A holder for HMODULE.
824FORCEINLINE void VoidFreeLibrary(HMODULE h) { WRAPPER_NO_CONTRACT; CLRFreeLibrary(h); }
825
826typedef Wrapper<HMODULE, DoNothing<HMODULE>, VoidFreeLibrary, NULL> ModuleHandleHolder;
827
828#ifndef FEATURE_PAL
829
830// A holder for memory blocks allocated by Windows. This holder (and any OS APIs you call
831// that allocate objects on your behalf) should not be used when the CLR is memory-hosted.
832
833FORCEINLINE void VoidFreeWinAllocatedBlock(LPVOID pv)
834{
835 LIMITED_METHOD_CONTRACT;
836
837#pragma push_macro("GetProcessHeap")
838#pragma push_macro("HeapFree")
839#undef GetProcessHeap
840#undef HeapFree
841 // 0: no special flags
842 ::HeapFree(::GetProcessHeap(), 0, pv);
843#pragma pop_macro("HeapFree")
844#pragma pop_macro("GetProcessHeap")
845}
846
847typedef Wrapper<LPVOID, DoNothing<LPVOID>, VoidFreeWinAllocatedBlock, NULL> WinAllocatedBlockHolder;
848
849#endif // !FEATURE_PAL
850
851// For debugging, we can track arbitrary Can't-Stop regions.
852// In V1.0, this was on the Thread object, but we need to track this for threads w/o a Thread object.
853FORCEINLINE void IncCantStopCount()
854{
855 ClrFlsIncrementValue(TlsIdx_CantStopCount, 1);
856}
857
858FORCEINLINE void DecCantStopCount()
859{
860 ClrFlsIncrementValue(TlsIdx_CantStopCount, -1);
861}
862
863typedef StateHolder<IncCantStopCount, DecCantStopCount> CantStopHolder;
864
865#ifdef _DEBUG
866// For debug-only, this can be used w/ a holder to ensure that we're keeping our CS count balanced.
867// We should never use this w/ control flow.
868inline int GetCantStopCount()
869{
870 return (int) (size_t) ClrFlsGetValue(TlsIdx_CantStopCount);
871}
872
873// At places where we know we're calling out to native code, we can assert that we're NOT in a CS region.
874// This is _debug only since we only use it for asserts; not for real code-flow control in a retail build.
875inline bool IsInCantStopRegion()
876{
877 return (GetCantStopCount() > 0);
878}
879#endif // _DEBUG
880
881
882// PAL does not support per-thread locales. The holder is no-op for FEATURE_PALs
883class ThreadLocaleHolder
884{
885#ifndef FEATURE_PAL
886public:
887
888 ThreadLocaleHolder()
889 {
890 m_locale = GetThreadLocale();
891 }
892
893 ~ThreadLocaleHolder();
894
895private:
896 LCID m_locale;
897#endif // !FEATURE_PAL
898};
899
900
901
902BOOL IsValidMethodCodeNotification(USHORT Notification);
903
904typedef DPTR(struct JITNotification) PTR_JITNotification;
905struct JITNotification
906{
907 USHORT state; // values from CLRDataMethodCodeNotification
908 TADDR clrModule;
909 mdToken methodToken;
910
911 JITNotification() { SetFree(); }
912 BOOL IsFree() { return state == CLRDATA_METHNOTIFY_NONE; }
913 void SetFree() { state = CLRDATA_METHNOTIFY_NONE; clrModule = NULL; methodToken = 0; }
914 void SetState(TADDR moduleIn, mdToken tokenIn, USHORT NType)
915 {
916 _ASSERTE(IsValidMethodCodeNotification(NType));
917 clrModule = moduleIn;
918 methodToken = tokenIn;
919 state = NType;
920 }
921};
922
923// The maximum number of TADDR sized arguments that the SOS exception notification can use
924#define MAX_CLR_NOTIFICATION_ARGS 3
925GARY_DECL(size_t, g_clrNotificationArguments, MAX_CLR_NOTIFICATION_ARGS);
926extern void InitializeClrNotifications();
927
928GPTR_DECL(JITNotification, g_pNotificationTable);
929GVAL_DECL(ULONG32, g_dacNotificationFlags);
930
931#if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE)
932
933inline void
934InitializeJITNotificationTable()
935{
936 g_pNotificationTable = new (nothrow) JITNotification[1001];
937}
938
939#endif // FEATURE_PAL && !DACCESS_COMPILE
940
941class JITNotifications
942{
943public:
944 JITNotifications(JITNotification *jitTable);
945 BOOL SetNotification(TADDR clrModule, mdToken token, USHORT NType);
946 USHORT Requested(TADDR clrModule, mdToken token);
947
948 // if clrModule is NULL, all active notifications are changed to NType
949 BOOL SetAllNotifications(TADDR clrModule,USHORT NType,BOOL *changedOut);
950 inline BOOL IsActive() { LIMITED_METHOD_CONTRACT; return m_jitTable!=NULL; }
951
952 UINT GetTableSize();
953#ifdef DACCESS_COMPILE
954 static JITNotification *InitializeNotificationTable(UINT TableSize);
955 // Updates target table from host copy
956 BOOL UpdateOutOfProcTable();
957#endif
958
959private:
960 UINT GetLength();
961 void IncrementLength();
962 void DecrementLength();
963
964 BOOL FindItem(TADDR clrModule, mdToken token, UINT *indexOut);
965
966 JITNotification *m_jitTable;
967};
968
969typedef DPTR(struct GcNotification) PTR_GcNotification;
970
971inline
972BOOL IsValidGcNotification(GcEvt_t evType)
973{ return (evType < GC_EVENT_TYPE_MAX); }
974
975#define CLRDATA_GC_NONE 0
976
977struct GcNotification
978{
979 GcEvtArgs ev;
980
981 GcNotification() { SetFree(); }
982 BOOL IsFree() { return ev.typ == CLRDATA_GC_NONE; }
983 void SetFree() { memset(this, 0, sizeof(*this)); ev.typ = (GcEvt_t) CLRDATA_GC_NONE; }
984 void Set(GcEvtArgs ev_)
985 {
986 _ASSERTE(IsValidGcNotification(ev_.typ));
987 ev = ev_;
988 }
989 BOOL IsMatch(GcEvtArgs ev_)
990 {
991 LIMITED_METHOD_CONTRACT;
992 if (ev.typ != ev_.typ)
993 {
994 return FALSE;
995 }
996 switch (ev.typ)
997 {
998 case GC_MARK_END:
999 if (ev_.condemnedGeneration == 0 ||
1000 (ev.condemnedGeneration & ev_.condemnedGeneration) != 0)
1001 {
1002 return TRUE;
1003 }
1004 break;
1005 default:
1006 break;
1007 }
1008
1009 return FALSE;
1010 }
1011};
1012
1013GPTR_DECL(GcNotification, g_pGcNotificationTable);
1014
1015class GcNotifications
1016{
1017public:
1018 GcNotifications(GcNotification *gcTable);
1019 BOOL SetNotification(GcEvtArgs ev);
1020 GcEvtArgs* GetNotification(GcEvtArgs ev)
1021 {
1022 LIMITED_METHOD_CONTRACT;
1023 UINT idx;
1024 if (FindItem(ev, &idx))
1025 {
1026 return &m_gcTable[idx].ev;
1027 }
1028 else
1029 {
1030 return NULL;
1031 }
1032 }
1033
1034 // if clrModule is NULL, all active notifications are changed to NType
1035 inline BOOL IsActive()
1036 { return m_gcTable != NULL; }
1037
1038 UINT GetTableSize()
1039 { return Size(); }
1040
1041#ifdef DACCESS_COMPILE
1042 static GcNotification *InitializeNotificationTable(UINT TableSize);
1043 // Updates target table from host copy
1044 BOOL UpdateOutOfProcTable();
1045#endif
1046
1047private:
1048 UINT& Length()
1049 {
1050 LIMITED_METHOD_CONTRACT;
1051 _ASSERTE(IsActive());
1052 UINT *pLen = (UINT *) &(m_gcTable[-1].ev.typ);
1053 return *pLen;
1054 }
1055 UINT& Size()
1056 {
1057 _ASSERTE(IsActive());
1058 UINT *pLen = (UINT *) &(m_gcTable[-1].ev.typ);
1059 return *(pLen+1);
1060 }
1061 void IncrementLength()
1062 { ++Length(); }
1063 void DecrementLength()
1064 { --Length(); }
1065
1066 BOOL FindItem(GcEvtArgs ev, UINT *indexOut);
1067
1068 GcNotification *m_gcTable;
1069};
1070
1071
1072class MethodDesc;
1073class Module;
1074
1075class DACNotify
1076{
1077public:
1078 // types
1079 enum {
1080 MODULE_LOAD_NOTIFICATION=1,
1081 MODULE_UNLOAD_NOTIFICATION=2,
1082 JIT_NOTIFICATION=3,
1083 JIT_PITCHING_NOTIFICATION=4,
1084 EXCEPTION_NOTIFICATION=5,
1085 GC_NOTIFICATION= 6,
1086 CATCH_ENTER_NOTIFICATION = 7,
1087 JIT_NOTIFICATION2=8,
1088 };
1089
1090 // called from the runtime
1091 static void DoJITNotification(MethodDesc *MethodDescPtr, TADDR NativeCodeLocation);
1092 static void DoJITPitchingNotification(MethodDesc *MethodDescPtr);
1093 static void DoModuleLoadNotification(Module *Module);
1094 static void DoModuleUnloadNotification(Module *Module);
1095 static void DoExceptionNotification(class Thread* ThreadPtr);
1096 static void DoGCNotification(const GcEvtArgs& evtargs);
1097 static void DoExceptionCatcherEnterNotification(MethodDesc *MethodDescPtr, DWORD nativeOffset);
1098
1099 // called from the DAC
1100 static int GetType(TADDR Args[]);
1101 static BOOL ParseJITNotification(TADDR Args[], TADDR& MethodDescPtr, TADDR& NativeCodeLocation);
1102 static BOOL ParseJITPitchingNotification(TADDR Args[], TADDR& MethodDescPtr);
1103 static BOOL ParseModuleLoadNotification(TADDR Args[], TADDR& ModulePtr);
1104 static BOOL ParseModuleUnloadNotification(TADDR Args[], TADDR& ModulePtr);
1105 static BOOL ParseExceptionNotification(TADDR Args[], TADDR& ThreadPtr);
1106 static BOOL ParseGCNotification(TADDR Args[], GcEvtArgs& evtargs);
1107 static BOOL ParseExceptionCatcherEnterNotification(TADDR Args[], TADDR& MethodDescPtr, DWORD& nativeOffset);
1108};
1109
1110void DACNotifyCompilationFinished(MethodDesc *pMethodDesc);
1111
1112#ifdef _DEBUG
1113#ifndef FEATURE_PAL
1114// NOTE: Windows Vista RTM SDK defines CaptureStackBackTrace as RtlCaptureStackBackTrace (in winbase.h)
1115// Renamed CaptureStackBackTrace to UtilCaptureBackTrace in order to avoid conflicts with the Windows definition
1116USHORT UtilCaptureStackBackTrace(
1117 ULONG FramesToSkip,
1118 ULONG FramesToCapture,
1119 PVOID * BackTrace,
1120 OUT PULONG BackTraceHash);
1121#endif // !FEATURE_PAL
1122#endif //_DEBUG
1123
1124
1125// These wrap the SString:L:CompareCaseInsenstive function in a way that makes it
1126// easy to fix code that uses _stricmp. _stricmp should be avoided as it uses the current
1127// C-runtime locale rather than the invariance culture.
1128//
1129// Note that unlike the real _stricmp, these functions unavoidably have a throws/gc_triggers/inject_fault
1130// contract. So if need a case-insensitive comparison in a place where you can't tolerate this contract,
1131// you've got a problem.
1132int __cdecl stricmpUTF8(const char* szStr1, const char* szStr2);
1133
1134#ifdef _DEBUG
1135class DisableDelayLoadCheckForOleaut32
1136{
1137public:
1138 DisableDelayLoadCheckForOleaut32();
1139 ~DisableDelayLoadCheckForOleaut32();
1140};
1141#endif
1142
1143extern LONG g_OLEAUT32_Loaded;
1144
1145#define ENSURE_OLEAUT32_LOADED()
1146
1147BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length);
1148
1149#ifndef DACCESS_COMPILE
1150// returns if ARM was already enabled or not.
1151BOOL EnableARM();
1152#endif // !DACCESS_COMPILE
1153
1154int GetRandomInt(int maxVal);
1155
1156class InternalCasingHelper {
1157
1158 private:
1159 // Convert szIn to lower case in the Invariant locale.
1160 // TODO: NLS Arrowhead -Called by the two ToLowers)
1161 static INT32 InvariantToLowerHelper(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn, BOOL fAllowThrow);
1162
1163 public:
1164 //
1165 // Native helper functions to do correct casing operations in
1166 // runtime native code.
1167 //
1168
1169 // Convert szIn to lower case in the Invariant locale. (WARNING: May throw.)
1170 static INT32 InvariantToLower(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn);
1171
1172 // Convert szIn to lower case in the Invariant locale. (WARNING: This version
1173 // won't throw but it will use stack space as an intermediary (so don't
1174 // use for ridiculously long strings.)
1175 static INT32 InvariantToLowerNoThrow(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn);
1176};
1177
1178//
1179//
1180// COMCHARACTER
1181//
1182//
1183class COMCharacter {
1184public:
1185 //These are here for support from native code. They are never called from our managed classes.
1186 static BOOL nativeIsWhiteSpace(WCHAR c);
1187 static BOOL nativeIsDigit(WCHAR c);
1188};
1189
1190#ifdef _DEBUG
1191#define FORCEINLINE_NONDEBUG
1192#else
1193#define FORCEINLINE_NONDEBUG FORCEINLINE
1194#endif
1195
1196#ifndef FEATURE_PAL
1197// Extract the file version from an executable.
1198HRESULT GetFileVersion(LPCWSTR wszFilePath, ULARGE_INTEGER* pFileVersion);
1199#endif // !FEATURE_PAL
1200
1201#endif /* _H_UTIL */
1202
1203