summaryrefslogtreecommitdiff
path: root/src/inc/palclr.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/inc/palclr.h')
-rw-r--r--src/inc/palclr.h605
1 files changed, 605 insertions, 0 deletions
diff --git a/src/inc/palclr.h b/src/inc/palclr.h
new file mode 100644
index 0000000000..808b3bb961
--- /dev/null
+++ b/src/inc/palclr.h
@@ -0,0 +1,605 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+// ===========================================================================
+// File: palclr.h
+//
+// Various macros and constants that are necessary to make the CLR portable.
+//
+
+// ===========================================================================
+
+
+#if !defined(FEATURE_PAL)
+
+#ifndef __PALCLR_H__
+#define __PALCLR_H__
+
+// This macro is used to standardize the wide character string literals between UNIX and Windows.
+// Unix L"" is UTF32, and on windows it's UTF16. Because of built-in assumptions on the size
+// of string literals, it's important to match behaviour between Unix and Windows. Unix will be defined
+// as u"" (char16_t)
+#ifdef PLATFORM_UNIX
+#define W(str) u##str
+#else // PLATFORM_UNIX
+#define W(str) L##str
+#endif // PLATFORM_UNIX
+
+#include <windef.h>
+
+#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
+#define _DEBUG_IMPL 1
+#endif
+
+//
+// CPP_ASSERT() can be used within a class definition, to perform a
+// compile-time assertion involving private names within the class.
+//
+// MS compiler doesn't allow redefinition of the typedef within a template.
+// gcc doesn't allow redefinition of the typedef within a class, though
+// it does at file scope.
+#define CPP_ASSERT(n, e) typedef char __C_ASSERT__##n[(e) ? 1 : -1];
+
+
+// PORTABILITY_ASSERT and PORTABILITY_WARNING macros are meant to be used to
+// mark places in the code that needs attention for portability. The usual
+// usage pattern is:
+//
+// int get_scratch_register() {
+// #if defined(_TARGET_X86_)
+// return eax;
+// #elif defined(_TARGET_AMD64_)
+// return rax;
+// #elif defined(_TARGET_ARM_)
+// return r0;
+// #else
+// PORTABILITY_ASSERT("scratch register");
+// return 0;
+// #endif
+// }
+//
+// PORTABILITY_ASSERT is meant to be used inside functions/methods. It can
+// introduce compile-time and/or run-time errors.
+// PORTABILITY_WARNING is meant to be used outside functions/methods. It can
+// introduce compile-time errors or warnings only.
+//
+// People starting new ports will first define these to just cause run-time
+// errors. Once they fix all the places that need attention for portability,
+// they can define PORTABILITY_ASSERT and PORTABILITY_WARNING to cause
+// compile-time errors to make sure that they haven't missed anything.
+//
+// If it is reasonably possible all codepaths containing PORTABILITY_ASSERT
+// should be compilable (e.g. functions should return NULL or something if
+// they are expected to return a value).
+//
+// The message in these two macros should not contain any keywords like TODO
+// or NYI. It should be just the brief description of the problem.
+
+#if defined(_TARGET_X86_)
+// Finished ports - compile-time errors
+#define PORTABILITY_WARNING(message) NEED_TO_PORT_THIS_ONE(NEED_TO_PORT_THIS_ONE)
+#define PORTABILITY_ASSERT(message) NEED_TO_PORT_THIS_ONE(NEED_TO_PORT_THIS_ONE)
+#else
+// Ports in progress - run-time asserts only
+#define PORTABILITY_WARNING(message)
+#define PORTABILITY_ASSERT(message) _ASSERTE(false && message)
+#endif
+
+
+#define DIRECTORY_SEPARATOR_CHAR_W W('\\')
+#define DIRECTORY_SEPARATOR_STR_W W("\\")
+
+#define PATH_SEPARATOR_CHAR_W W(';')
+
+// PAL Macros
+// Not all compilers support fully anonymous aggregate types, so the
+// PAL provides names for those types. To allow existing definitions of
+// those types to continue to work, we provide macros that should be
+// used to reference fields within those types.
+
+#ifndef DECIMAL_SCALE
+#define DECIMAL_SCALE(dec) ((dec).scale)
+#endif
+
+#ifndef DECIMAL_SIGN
+#define DECIMAL_SIGN(dec) ((dec).sign)
+#endif
+
+#ifndef DECIMAL_SIGNSCALE
+#define DECIMAL_SIGNSCALE(dec) ((dec).signscale)
+#endif
+
+#ifndef DECIMAL_LO32
+#define DECIMAL_LO32(dec) ((dec).Lo32)
+#endif
+
+#ifndef DECIMAL_MID32
+#define DECIMAL_MID32(dec) ((dec).Mid32)
+#endif
+
+#ifndef DECIMAL_HI32
+#define DECIMAL_HI32(dec) ((dec).Hi32)
+#endif
+
+#ifndef DECIMAL_LO64_GET
+#define DECIMAL_LO64_GET(dec) ((dec).Lo64)
+#endif
+
+#ifndef DECIMAL_LO64_SET
+#define DECIMAL_LO64_SET(dec,value) {(dec).Lo64 = value; }
+#endif
+
+#ifndef IMAGE_RELOC_FIELD
+#define IMAGE_RELOC_FIELD(img, f) ((img).f)
+#endif
+
+#ifndef IMAGE_IMPORT_DESC_FIELD
+#define IMAGE_IMPORT_DESC_FIELD(img, f) ((img).f)
+#endif
+
+//Remove these "unanonymous" unions from newer builds for now. Confirm that they were never needed when we
+//bring back Rotor.
+#define IMAGE_RDE_ID(img) ((img)->Id)
+#ifndef IMAGE_RDE_ID
+#define IMAGE_RDE_ID(img) ((img)->Id)
+#endif
+
+#define IMAGE_RDE_NAME(img) ((img)->Name)
+#ifndef IMAGE_RDE_NAME
+#define IMAGE_RDE_NAME(img) ((img)->Name)
+#endif
+
+#define IMAGE_RDE_OFFSET(img) ((img)->OffsetToData)
+#ifndef IMAGE_RDE_OFFSET
+#define IMAGE_RDE_OFFSET(img) ((img)->OffsetToData)
+#endif
+
+#ifndef IMAGE_RDE_NAME_FIELD
+#define IMAGE_RDE_NAME_FIELD(img, f) ((img)->f)
+#endif
+
+#define IMAGE_RDE_OFFSET_FIELD(img, f) ((img)->f)
+#ifndef IMAGE_RDE_OFFSET_FIELD
+#define IMAGE_RDE_OFFSET_FIELD(img, f) ((img)->f)
+#endif
+
+#ifndef IMAGE_FE64_FIELD
+#define IMAGE_FE64_FIELD(img, f) ((img).f)
+#endif
+
+#ifndef IMPORT_OBJ_HEADER_FIELD
+#define IMPORT_OBJ_HEADER_FIELD(obj, f) ((obj).f)
+#endif
+
+#ifndef IMAGE_COR20_HEADER_FIELD
+#define IMAGE_COR20_HEADER_FIELD(obj, f) ((obj).f)
+#endif
+
+
+// PAL Numbers
+// Used to ensure cross-compiler compatibility when declaring large
+// integer constants. 64-bit integer constants should be wrapped in the
+// declarations listed here.
+//
+// Each of the #defines here is wrapped to avoid conflicts with rotor_pal.h.
+
+#if defined(_MSC_VER)
+
+// MSVC's way of declaring large integer constants
+// If you define these in one step, without the _HELPER macros, you
+// get extra whitespace when composing these with other concatenating macros.
+#ifndef I64
+#define I64_HELPER(x) x ## i64
+#define I64(x) I64_HELPER(x)
+#endif
+
+#ifndef UI64
+#define UI64_HELPER(x) x ## ui64
+#define UI64(x) UI64_HELPER(x)
+#endif
+
+#else
+
+// GCC's way of declaring large integer constants
+// If you define these in one step, without the _HELPER macros, you
+// get extra whitespace when composing these with other concatenating macros.
+#ifndef I64
+#define I64_HELPER(x) x ## LL
+#define I64(x) I64_HELPER(x)
+#endif
+
+#ifndef UI64
+#define UI64_HELPER(x) x ## ULL
+#define UI64(x) UI64_HELPER(x)
+#endif
+
+#endif
+
+
+// PAL SEH
+// Macros for portable exception handling. The Win32 SEH is emulated using
+// these macros and setjmp/longjmp on Unix
+//
+// Usage notes:
+//
+// - The filter has to be a function taking two parameters:
+// LONG MyFilter(PEXCEPTION_POINTERS *pExceptionInfo, PVOID pv)
+//
+// - It is not possible to directly use the local variables in the filter.
+// All the local information that the filter has to need to know about should
+// be passed through pv parameter
+//
+// - Do not use goto to jump out of the PAL_TRY block
+// (jumping out of the try block is not a good idea even on Win32, because of
+// it causes stack unwind)
+//
+// - It is not possible to directly use the local variables in the try block.
+// All the local information that the filter has to need to know about should
+// be passed through pv parameter
+//
+//
+// Simple examples:
+//
+// struct Param { ... local variables used in try block and filter ... } param;
+// PAL_TRY(Param *, pParam, &param) { // read as: Param *pParam = &param;
+// ....
+// } PAL_FINALLY {
+// ....
+// }
+// PAL_ENDTRY
+//
+//
+// struct Param { ... local variables used in try block and filter ... } param;
+// PAL_TRY(Param *, pParam, &param) {
+// ....
+// } PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+// ....
+// }
+// PAL_ENDTRY
+//
+//
+// LONG MyFilter(PEXCEPTION_POINTERS *pExceptionInfo, PVOID pv)
+// {
+// ...
+// }
+// PAL_TRY(void *, unused, NULL) {
+// ....
+// } PAL_EXCEPT_FILTER(MyFilter) {
+// ....
+// }
+// PAL_ENDTRY
+//
+//
+// Complex example:
+//
+// struct MyParams
+// {
+// ...
+// } params;
+//
+// PAL_TRY(MyParams *, pMyParamsOuter, &params) {
+// PAL_TRY(MyParams *, pMyParamsInnter, pMyParamsOuter) {
+// ...
+// if (error) goto Done;
+// ...
+// Done: ;
+// } PAL_EXCEPT_FILTER(OtherFilter) {
+// ...
+// }
+// PAL_ENDTRY
+// }
+// PAL_FINALLY {
+// }
+// PAL_ENDTRY
+//
+
+#include "staticcontract.h"
+
+// Note: PAL_SEH_RESTORE_GUARD_PAGE is only ever defined in clrex.h, so we only restore guard pages automatically
+// when these macros are used from within the VM.
+#define PAL_SEH_RESTORE_GUARD_PAGE
+
+#define PAL_TRY_NAKED \
+ { \
+ bool __exHandled; __exHandled = false; \
+ DWORD __exCode; __exCode = 0; \
+ SCAN_EHMARKER(); \
+ __try \
+ { \
+ SCAN_EHMARKER_TRY();
+
+#define PAL_EXCEPT_NAKED(Disposition) \
+ } \
+ __except(__exCode = GetExceptionCode(), Disposition) \
+ { \
+ __exHandled = true; \
+ SCAN_EHMARKER_CATCH(); \
+ PAL_SEH_RESTORE_GUARD_PAGE
+
+#define PAL_EXCEPT_FILTER_NAKED(pfnFilter, param) \
+ } \
+ __except(__exCode = GetExceptionCode(), \
+ pfnFilter(GetExceptionInformation(), param)) \
+ { \
+ __exHandled = true; \
+ SCAN_EHMARKER_CATCH(); \
+ PAL_SEH_RESTORE_GUARD_PAGE
+
+#define PAL_FINALLY_NAKED \
+ } \
+ __finally \
+ { \
+
+#define PAL_ENDTRY_NAKED \
+ } \
+ PAL_ENDTRY_NAKED_DBG \
+ } \
+
+
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
+//
+// In debug mode, compile the try body as a method of a local class.
+// This way, the compiler will check that the body is not directly
+// accessing any local variables and arguments.
+//
+#define PAL_TRY(__ParamType, __paramDef, __paramRef) \
+{ \
+ __ParamType __param = __paramRef; \
+ __ParamType __paramToPassToFilter = __paramRef; \
+ class __Body \
+ { \
+ public: \
+ static void Run(__ParamType __paramDef) \
+ { \
+ PAL_TRY_HANDLER_DBG_BEGIN
+
+// PAL_TRY implementation that abstracts usage of COMPILER_INSTANCE*, which is used by
+// JIT64. On Windows, we dont need to do anything special as we dont have nested classes/methods
+// as on PAL.
+#define PAL_TRY_CI(__ParamType, __paramDef, __paramRef) \
+{ \
+ struct __HandlerData { \
+ __ParamType __param; \
+ COMPILER_INSTANCE *__ciPtr; \
+ }; \
+ __HandlerData handlerData; \
+ handlerData.__param = __paramRef; \
+ handlerData.__ciPtr = ciPtr; \
+ __HandlerData* __param = &handlerData; \
+ __ParamType __paramToPassToFilter = __paramRef; \
+ class __Body \
+ { \
+ public: \
+ static void Run(__HandlerData* __pHandlerData) \
+ { \
+ PAL_TRY_HANDLER_DBG_BEGIN \
+ COMPILER_INSTANCE *ciPtr = __pHandlerData->__ciPtr; \
+ __ParamType __paramDef = __pHandlerData->__param;
+
+
+#define PAL_TRY_FOR_DLLMAIN(__ParamType, __paramDef, __paramRef, __reason) \
+{ \
+ __ParamType __param = __paramRef; \
+ __ParamType __paramToPassToFilter = __paramRef; \
+ class __Body \
+ { \
+ public: \
+ static void Run(__ParamType __paramDef) \
+ { \
+ PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(__reason)
+
+#define PAL_EXCEPT(Disposition) \
+ PAL_TRY_HANDLER_DBG_END \
+ } \
+ }; \
+ PAL_TRY_NAKED \
+ __Body::Run(__param); \
+ PAL_EXCEPT_NAKED(Disposition)
+
+#define PAL_EXCEPT_FILTER(pfnFilter) \
+ PAL_TRY_HANDLER_DBG_END \
+ } \
+ }; \
+ PAL_TRY_NAKED \
+ __Body::Run(__param); \
+ PAL_EXCEPT_FILTER_NAKED(pfnFilter, __paramToPassToFilter)
+
+#define PAL_FINALLY \
+ PAL_TRY_HANDLER_DBG_END \
+ } \
+ }; \
+ PAL_TRY_NAKED \
+ __Body::Run(__param); \
+ PAL_FINALLY_NAKED
+
+#define PAL_ENDTRY \
+ PAL_ENDTRY_NAKED \
+}
+
+#else // _DEBUG
+
+#define PAL_TRY(__ParamType, __paramDef, __paramRef) \
+{ \
+ __ParamType __param = __paramRef; \
+ __ParamType __paramDef = __param; \
+ PAL_TRY_NAKED \
+ PAL_TRY_HANDLER_DBG_BEGIN
+
+// PAL_TRY implementation that abstracts usage of COMPILER_INSTANCE*, which is used by
+// JIT64. On Windows, we dont need to do anything special as we dont have nested classes/methods
+// as on PAL.
+#define PAL_TRY_CI(__ParamType, __paramDef, __paramRef) PAL_TRY(__ParamType, __paramDef, __paramRef)
+
+#define PAL_TRY_FOR_DLLMAIN(__ParamType, __paramDef, __paramRef, __reason) \
+{ \
+ __ParamType __param = __paramRef; \
+ __ParamType __paramDef; __paramDef = __param; \
+ PAL_TRY_NAKED \
+ PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(__reason)
+
+#define PAL_EXCEPT(Disposition) \
+ PAL_TRY_HANDLER_DBG_END \
+ PAL_EXCEPT_NAKED(Disposition)
+
+#define PAL_EXCEPT_FILTER(pfnFilter) \
+ PAL_TRY_HANDLER_DBG_END \
+ PAL_EXCEPT_FILTER_NAKED(pfnFilter, __param)
+
+#define PAL_FINALLY \
+ PAL_TRY_HANDLER_DBG_END \
+ PAL_FINALLY_NAKED
+
+#define PAL_ENDTRY \
+ PAL_ENDTRY_NAKED \
+ }
+
+#endif // _DEBUG
+
+// Executes the handler if the specified exception code matches
+// the one in the exception. Otherwise, returns EXCEPTION_CONTINUE_SEARCH.
+#define PAL_EXCEPT_IF_EXCEPTION_CODE(dwExceptionCode) PAL_EXCEPT((GetExceptionCode() == dwExceptionCode)?EXCEPTION_EXECUTE_HANDLER:EXCEPTION_CONTINUE_SEARCH)
+
+#define PAL_CPP_TRY try
+#define PAL_CPP_ENDTRY
+#define PAL_CPP_THROW(type, obj) do { SCAN_THROW_MARKER; throw obj; } while (false)
+#define PAL_CPP_RETHROW do { SCAN_THROW_MARKER; throw; } while (false)
+#define PAL_CPP_CATCH_DERIVED(type, obj) catch (type * obj)
+#define PAL_CPP_CATCH_ALL catch (...)
+#define PAL_CPP_CATCH_EXCEPTION_NOARG catch (Exception *)
+
+
+// SELECTANY macro is intended to prevent duplication of static const
+// arrays declared in .h files in binary modules.
+// The problem is that const variables have static internal linkage
+// in C++. That means that if a const variable is declared in a .h file
+// the compiler will emit it into every translation unit that uses that .h file.
+// That will cause duplication of the data when those translation units
+// are linked into a binary module.
+// SELECTANY declares a variable as extern to give it external linkage
+// and it provides __declspec(selectany) to instruct the linker to merge
+// duplicate external const static data copies into one.
+//
+#define SELECTANY extern __declspec(selectany)
+
+
+#if defined(_DEBUG_IMPL) && !defined(JIT_BUILD) && !defined(JIT64_BUILD) && !defined(CROSS_COMPILE) && !defined(_TARGET_ARM_) // @ARMTODO: no contracts for speed
+#define PAL_TRY_HANDLER_DBG_BEGIN \
+ BOOL ___oldOkayToThrowValue = FALSE; \
+ SO_INFRASTRUCTURE_CODE(BOOL ___oldSOTolerantState = FALSE;) \
+ ClrDebugState *___pState = ::GetClrDebugState(); \
+ __try \
+ { \
+ ___oldOkayToThrowValue = ___pState->IsOkToThrow(); \
+ SO_INFRASTRUCTURE_CODE(___oldSOTolerantState = ___pState->IsSOTolerant();) \
+ ___pState->SetOkToThrow(); \
+ PAL_ENTER_THROWS_REGION;
+
+// Special version that avoids touching the debug state after doing work in a DllMain for process or thread detach.
+#define PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason) \
+ BOOL ___oldOkayToThrowValue = FALSE; \
+ SO_INFRASTRUCTURE_CODE(BOOL ___oldSOTolerantState = FALSE;) \
+ ClrDebugState *___pState = NULL; \
+ if (_reason != DLL_PROCESS_ATTACH) \
+ ___pState = CheckClrDebugState(); \
+ __try \
+ { \
+ if (___pState) \
+ { \
+ ___oldOkayToThrowValue = ___pState->IsOkToThrow(); \
+ SO_INFRASTRUCTURE_CODE(___oldSOTolerantState = ___pState->IsSOTolerant();) \
+ ___pState->SetOkToThrow(); \
+ } \
+ if ((_reason == DLL_PROCESS_DETACH) || (_reason == DLL_THREAD_DETACH)) \
+ { \
+ ___pState = NULL; \
+ } \
+ PAL_ENTER_THROWS_REGION;
+
+#define PAL_TRY_HANDLER_DBG_END \
+ PAL_LEAVE_THROWS_REGION \
+ } \
+ __finally \
+ { \
+ if (___pState != NULL) \
+ { \
+ _ASSERTE(___pState == CheckClrDebugState()); \
+ ___pState->SetOkToThrow( ___oldOkayToThrowValue ); \
+ SO_INFRASTRUCTURE_CODE(___pState->SetSOTolerance( ___oldSOTolerantState );) \
+ } \
+ }
+
+#define PAL_ENDTRY_NAKED_DBG \
+ if (__exHandled) \
+ { \
+ RESTORE_SO_TOLERANCE_STATE; \
+ } \
+
+#else
+#define PAL_TRY_HANDLER_DBG_BEGIN ANNOTATION_TRY_BEGIN;
+#define PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason) ANNOTATION_TRY_BEGIN;
+#define PAL_TRY_HANDLER_DBG_END ANNOTATION_TRY_END;
+#define PAL_ENDTRY_NAKED_DBG
+#endif // defined(ENABLE_CONTRACTS_IMPL) && !defined(JIT64_BUILD)
+
+
+#if !BIGENDIAN
+// For little-endian machines, do nothing
+#define VAL16(x) x
+#define VAL32(x) x
+#define VAL64(x) x
+#define SwapString(x)
+#define SwapStringLength(x, y)
+#define SwapGuid(x)
+#endif // !BIGENDIAN
+
+#ifdef _MSC_VER
+// Get Unaligned values from a potentially unaligned object
+#define GET_UNALIGNED_16(_pObject) (*(UINT16 UNALIGNED *)(_pObject))
+#define GET_UNALIGNED_32(_pObject) (*(UINT32 UNALIGNED *)(_pObject))
+#define GET_UNALIGNED_64(_pObject) (*(UINT64 UNALIGNED *)(_pObject))
+
+// Set Value on an potentially unaligned object
+#define SET_UNALIGNED_16(_pObject, _Value) (*(UNALIGNED UINT16 *)(_pObject)) = (UINT16)(_Value)
+#define SET_UNALIGNED_32(_pObject, _Value) (*(UNALIGNED UINT32 *)(_pObject)) = (UINT32)(_Value)
+#define SET_UNALIGNED_64(_pObject, _Value) (*(UNALIGNED UINT64 *)(_pObject)) = (UINT64)(_Value)
+
+// Get Unaligned values from a potentially unaligned object and swap the value
+#define GET_UNALIGNED_VAL16(_pObject) VAL16(GET_UNALIGNED_16(_pObject))
+#define GET_UNALIGNED_VAL32(_pObject) VAL32(GET_UNALIGNED_32(_pObject))
+#define GET_UNALIGNED_VAL64(_pObject) VAL64(GET_UNALIGNED_64(_pObject))
+
+// Set a swap Value on an potentially unaligned object
+#define SET_UNALIGNED_VAL16(_pObject, _Value) SET_UNALIGNED_16(_pObject, VAL16((UINT16)_Value))
+#define SET_UNALIGNED_VAL32(_pObject, _Value) SET_UNALIGNED_32(_pObject, VAL32((UINT32)_Value))
+#define SET_UNALIGNED_VAL64(_pObject, _Value) SET_UNALIGNED_64(_pObject, VAL64((UINT64)_Value))
+#endif
+
+#ifdef _WIN64
+#define VALPTR(x) VAL64(x)
+#define GET_UNALIGNED_PTR(x) GET_UNALIGNED_64(x)
+#define GET_UNALIGNED_VALPTR(x) GET_UNALIGNED_VAL64(x)
+#define SET_UNALIGNED_PTR(p,x) SET_UNALIGNED_64(p,x)
+#define SET_UNALIGNED_VALPTR(p,x) SET_UNALIGNED_VAL64(p,x)
+#else
+#define VALPTR(x) VAL32(x)
+#define GET_UNALIGNED_PTR(x) GET_UNALIGNED_32(x)
+#define GET_UNALIGNED_VALPTR(x) GET_UNALIGNED_VAL32(x)
+#define SET_UNALIGNED_PTR(p,x) SET_UNALIGNED_32(p,x)
+#define SET_UNALIGNED_VALPTR(p,x) SET_UNALIGNED_VAL32(p,x)
+#endif
+
+#define MAKEDLLNAME_W(name) name W(".dll")
+#define MAKEDLLNAME_A(name) name ".dll"
+
+#ifdef UNICODE
+#define MAKEDLLNAME(x) MAKEDLLNAME_W(x)
+#else
+#define MAKEDLLNAME(x) MAKEDLLNAME_A(x)
+#endif
+
+#endif // __PALCLR_H__
+
+#include "palclr_win.h"
+
+#endif // !defined(FEATURE_PAL)